ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Errorstack 诊断 ORA-01000:maximum open cursors exceeded 的 open_cursors 配置与游标泄漏排查

Errorstack 诊断 ORA-01000:maximum open cursors exceeded 的 open_cursors 配置与游标泄漏排查 1. 从一次 ORA-01000 报错说起游标到底被谁占满了应用日志里突然刷出ORA-01000: maximum open cursors exceeded通常意味着某个会话打开的游标数量超过了open_cursors参数允许的上限。这个报错本身不复杂麻烦的是它只告诉你“超了”不告诉你“谁没关”。如果只是把open_cursors从 300 调到 3000可能撑几天又爆因为根因往往是代码里Statement/ResultSet没关或者循环里反复创建游标却不释放。我处理这类问题的思路是先用 Errorstack 在报错瞬间把会话的游标现场 dump 下来看清是哪些 SQL、哪些游标状态卡在 BOUND再结合v$open_cursor和open_cursors参数判断是配置偏小还是泄漏。下面按“复现报错 → 设置 Errorstack → 抓 trace → 分析游标 → 调整参数 → 验证修复”走一遍你可以直接照着在测试库上做一次。适合谁看Oracle DBA、Java/中间件开发、需要定位连接池游标泄漏的运维同学。核心检索词就是 Errorstack、ORA-01000、open_cursors、游标泄漏。2. 前置准备TaoToken 与排查环境排查过程中如果要用大模型帮你读 trace、解释游标状态或者让 coding agent 辅助写诊断脚本可以先把 TaoToken 的接入配好。它提供 OpenAI 兼容接口模型对话、API Key、Coding Plan 都有独立入口按需选即可。官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 基址https://taotoken.net/api模型对话验证模型是否可用https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewriteCoding Plan长期编码/Agent 场景https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite控制台https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keyshttps://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteOracle 侧需要一个可复现的测试库11g/12c/19c 均可、能执行alter system的权限、能访问diag/rdbms/db/inst/trace目录。Java 侧准备一个故意不关游标的 demo用来制造泄漏。3. 可复制配置复现 ORA-01000 并挂上 Errorstack3.1 先把 open_cursors 调小制造报错为了快速复现把参数临时调小。生产上不要这么干测试库随意。-- 查看当前值 show parameter open_cursors; -- 临时调小到 15方便复现 alter system set open_cursors15 scopeboth; -- 确认 show parameter open_cursors;scopeboth表示内存和 spfile 同时生效重启后仍是 15。复现完记得改回去。3.2 设置 Errorstack 事件Errorstack 的作用是当指定错误号出现时自动 dump 错误栈、进程栈和会话游标信息。针对 ORA-01000事件号就是 1000。-- 实例级出现 ORA-01000 时 dump level 3 alter system set events 1000 trace name errorstack level 3; -- 排查结束后关闭 alter system set events 1000 trace name context off;Errorstack 的级别含义Level内容1错误堆栈 函数调用堆栈2Level 1 ProcessState3Level 2 Context area显示所有 cursors重点显示当前 cursor排查游标泄漏用 level 3因为只有它会把会话打开的游标列表打出来。也可以只在某个会话上设置alter session set events 1000 trace name errorstack level 3;3.3 用 Java demo 触发泄漏下面这段代码在循环里反复createStatement和executeQuery但只在 finally 里关最后一次的rset/stmt前面的游标全部泄漏。循环 300 次open_cursors15必然报 ORA-01000。import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class TestCursor { public static void main(String args[]) throws Exception { Connection con null; Statement stmt null; ResultSet rset null; try { Class.forName(oracle.jdbc.driver.OracleDriver); String url jdbc:oracle:thin:127.0.0.1:1521:ora11; con DriverManager.getConnection(url, test, test); for (int i 0; i 300; i) { stmt con.createStatement(); rset stmt.executeQuery(select * from test); while (rset.next()) { rset.getString(1); } // 注意这里没有 close游标持续累积 } } catch (Exception e) { e.printStackTrace(); } finally { try { if (rset ! null) rset.close(); if (stmt ! null) stmt.close(); if (con ! null) con.close(); } catch (Exception e) { e.printStackTrace(); } } } }运行后会看到类似堆栈java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误 ORA-01000: 超出打开游标的最大数 ORA-00604: 递归 SQL 级别 1 出现错误 ORA-01000: 超出打开游标的最大数 ORA-01000: 超出打开游标的最大数 at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445) ... at TestCursor.main(TestCursor.java:19)4. 验证请求与成功结果读 trace 定位泄漏游标4.1 找到 trace 文件报错后alert 日志里会出现类似OS Pid: 8588 executed alter system set events 1000 trace name errorstack level 3 Errors in file f:\app\administrator\diag\rdbms\ora11\ora11\trace\ora11_ora_8764.trc: ORA-01000: 超出打开游标的最大数打开ora11_ora_8764.trc重点看Session Cursor Dump和Session Open Cursors两段。4.2 解读游标 dump----- Session Cursor Dump ----- Current cursor: 0, pgadep0 Open cursors(pls, sys, hwm, max): 15(0, 3, 15, 15) NULL0 SYNTAX0 PARSE0 BOUND15 FETCH0 ROW0Open cursors(...): 15(0, 3, 15, 15)说明当前会话打开了 15 个游标其中 3 个是系统递归游标高水位和上限都是 15。BOUND15表示 15 个游标全部处于 BOUND 状态——已经绑定但没关闭典型的泄漏特征。继续往下看----- Session Open Cursors ----- Cursor#1(0x000000001BD91998) stateBOUND curiob0x000000001BDAD5B0 Cursor#5(0x000000001BD91BD8) stateBOUND curiob0x000000001CBD94E8 ----- Dump Cursor sql_idc99yw1xkb4f1u xsc0x000000001CBD94E8 cur0x000000001BD91BD8 ----- ObjectName: Nameselect * from test Cursor#6(0x000000001BD91C68) stateBOUND curiob0x000000001CBD8958 ----- Dump Cursor sql_idc99yw1xkb4f1u xsc0x000000001CBD8958 cur0x000000001BD91C68 ----- ObjectName: Nameselect * from test Cursor#9(0x000000001BD91E18) stateBOUND curiob0x000000001CBD66A8 ----- Dump Cursor sql_idc99yw1xkb4f1u xsc0x000000001CBD66A8 cur0x000000001BD91E18 ----- ObjectName: Nameselect * from test多个游标指向同一个sql_idc99yw1xkb4f1uSQL 文本都是select * from test。这说明应用在循环里反复执行同一条 SQL每次新建游标却不关闭。到这里根因就清楚了不是open_cursors太小而是代码泄漏。4.3 用 v$open_cursor 交叉验证在报错会话还活着的时候可以查-- 按会话统计打开的游标数 select s.sid, s.serial#, s.username, count(*) as cursor_cnt from v$open_cursor o, v$session s where o.sid s.sid group by s.sid, s.serial#, s.username order by cursor_cnt desc; -- 看具体是哪些 SQL select sid, sql_id, sql_text from v$open_cursor where sid 问题会话SID order by sql_id;如果某个 SID 的游标数接近open_cursors且 SQL 高度重复基本可以确认泄漏点。5. 本篇常见错排查5.1 Errorstack 设了但没生成 trace先确认事件是否真的生效select name, value from v$parameter where name event; -- 或 show parameter event;如果没看到1000 trace name errorstack level 3可能是alter system没执行成功或者被其他 event 覆盖。另外 trace 目录权限不足也会导致写不进去检查background_dump_dest和user_dump_dest。5.2 报错是 ORA-01000 但 trace 里没有 Session Open Cursors大概率是 level 设成了 1 或 2。只有 level 3 才包含 Context area。改成 level 3 重新触发。5.3 调大 open_cursors 后不报错了但连接池还是异常open_cursors是会话级上限调大只是延后爆发。如果v$open_cursor里某个会话游标数持续增长不回落说明泄漏仍在。正确做法是修代码Statement、PreparedStatement、ResultSet用完即关推荐 try-with-resources。try (Connection con DriverManager.getConnection(url, user, pwd); PreparedStatement ps con.prepareStatement(select * from test); ResultSet rs ps.executeQuery()) { while (rs.next()) { rs.getString(1); } }5.4 参数改了没生效open_cursors是动态参数scopeboth立即生效。但如果用scopespfile需要重启。另外 RAC 环境要在每个实例上确认或者用sid*。alter system set open_cursors1000 scopeboth sid*;5.5 排查完忘记关 Errorstack事件会一直挂在实例上每次 ORA-01000 都 dumptrace 目录可能被撑爆。排查结束务必执行alter system set events 1000 trace name context off;6. 收尾与后续接入整个链路走下来调小open_cursors复现 → 挂 Errorstack level 3 → 跑泄漏 demo → 读 trace 看到多个 BOUND 游标指向同一 sql_id → 用v$open_cursor确认 → 修代码用 try-with-resources → 把open_cursors调回合理值。根因是游标泄漏不是参数太小这一点在 trace 里看得很清楚。如果你想让 coding agent 帮你批量扫描项目里没关的Statement或者用模型解释 trace 里的游标状态可以走 Coding Plan 和模型对话入口API Key 和接入文档在下面API Keyshttps://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite模型对话https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewriteCoding Planhttps://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite最后提醒一句生产库上设 Errorstack 前先确认 trace 目录空间level 3 的 dump 在游标多的时候文件会比较大别把磁盘写满。
返回列表