显式游标必须配对open/close,不会随pl/sql块结束自动关闭;异常路径中须用if c%isopen then close c;确保释放,否则导致ora-01000游标泄漏。

存储过程里显式游标必须配对 OPEN/CLOSE
显式游标(CURSOR c IS SELECT ...)不会随 PL/SQL 块结束自动关闭,尤其在异常跳转时极易漏关。漏掉 CLOSE 会导致该会话持续持有游标句柄,叠加触发 ORA-01000。
- 所有
OPEN后必须紧跟CLOSE,且不能只写在正常流程末尾 - 在
EXCEPTION块中也要检查c%ISOPEN并手动CLOSE - 避免把
OPEN放在循环体内——同一游标反复打开会快速耗尽OPEN_CURSORS - 优先用
FOR r IN (SELECT ...)替代手动控制:它隐式完成 OPEN/FETCH/CLOSE,只要不中途异常退出就不会漏关
SYS_REFCURSOR 的关闭责任不在存储过程内
当存储过程通过 OUT SYS_REFCURSOR 返回结果集时,OPEN 是它的义务,CLOSE 是调用方的责任。在过程里提前 CLOSE 会导致调用方收到已关闭游标,报 ORA-01001;不关则泄漏由客户端承担。
- 存储过程只需做:
OPEN p_cursor FOR SELECT ...,绝不CLOSE p_cursor - JDBC 调用时,必须调用
CallableStatement.close()才释放服务端游标;ResultSet.close()不够 - 若用 Spring
SimpleJdbcCall,确认未开启语句缓存(setStatementsCacheSize(0)),否则复用CallableStatement可能掩盖关闭缺失
BULK COLLECT 不加 LIMIT 就是 PGA 内存炸弹
BULK COLLECT INTO 会把整批结果全加载进 PGA 内存。没设 LIMIT 时,查一张千万行表可能直接 OOM,且集合对象不显式清空(collection.DELETE)会持续引用内存。
- 强制使用
FETCH c BULK COLLECT INTO t_array LIMIT 1000,数值按单行大小和可用 PGA 估算 - 每次 FETCH 后立即处理数据,并执行
t_array.DELETE释放引用 - 禁止对大结果集用无 LIMIT 的
SELECT ... BULK COLLECT INTO—— Oracle 允许,但 PL/SQL 引擎可能静默失败或报PLS-00302
别依赖作用域自动清理,异常路径最危险
有人以为声明在 BEGIN...END 块里的游标会在块退出时自动关闭。这仅在“无异常、未传出、标准 PL/SQL 环境”下才成立。一旦抛异常、游标被赋值给包变量、或 JDBC 封装匿名块,隐式关闭就失效。
- 显式
CLOSE是唯一可靠方式,比任何“理论上应该关闭”的假设都管用 - 监控真实 PGA 消耗比调高
open_cursors更有效:SELECT name, value/1024/1024 "MB" FROM v$pgastat WHERE name IN ('total PGA allocated', 'total PGA used mem') - 查泄漏源头用:
SELECT sid, count(*) FROM v$open_cursor GROUP BY sid ORDER BY 2 DESC,再关联v$session定位应用会话
IF c%ISOPEN THEN CLOSE c; —— 它不炫技,但缺了它,游标就永远卡在那儿。











