显式游标编译期绑定SQL、强类型、需手动关闭,适用于固定结构批处理;游标变量运行时动态赋值、弱类型(可强类型化)、由调用方关闭,适用于灵活查询和结果集传递。

显式游标必须在编译期绑定 SQL,游标变量可运行时动态赋值
显式游标(CURSOR c IS SELECT ...)的查询语句在 PL/SQL 块编译时就固定了,不能换;而游标变量(SYS_REFCURSOR)本身不带 SQL,只是一块“指针容器”,你可以在运行时用 OPEN ... FOR 把任意合法查询赋给它。这意味着:一个存储过程接收不同条件、返回不同列的查询结果,用游标变量就能统一入口,显式游标做不到。
常见错误现象:PLS-00382: expression is of wrong type——把显式游标类型变量误当游标变量传参;或反过来,用 OPEN c FOR ... 给显式游标赋值(语法直接报错)。
使用场景建议:
- 固定结构、固定逻辑的批处理(如每天更新
emp_demo表薪资)→ 用显式游标,编译期校验强,IDE 提示准 - 报表服务接口、前端按筛选条件查不同视图 → 必须用
SYS_REFCURSOR,否则得写 N 个重载过程 - 需要把结果集传给另一个过程做后续加工 → 只能用游标变量,显式游标无法作为参数传递
显式游标有强类型约束,游标变量默认是弱类型
显式游标声明时带 RETURN 子句(如 CURSOR c RETURN emp_demo%ROWTYPE),编译器会严格检查 FETCH 到的变量是否匹配;游标变量默认不声明返回结构,FETCH 前必须先知道字段名和类型,否则运行时报 ORA-06504: PL/SQL: Return types of Result Set variables or query do not match。
性能影响:强类型显式游标在解析阶段就能做更多优化,执行计划更稳定;游标变量因 SQL 在运行时才确定,每次 OPEN 都可能触发硬解析(除非用了绑定变量 + 合理的共享池设置)。
实操建议:
- 若坚持用游标变量又想获得类型安全,可声明强类型 REF CURSOR:
TYPE emp_refcur IS REF CURSOR RETURN emp_demo%ROWTYPE; - 但注意:强类型 REF CURSOR 仍不能像显式游标那样在声明处直接写 SQL,它只是限制了后续
OPEN ... FOR能接的查询结构 - 弱类型
SYS_REFCURSOR更灵活,但必须靠文档或调用方约定字段顺序,否则 FETCH INTO 容易错位
生命周期管理差异:显式游标必须手动 CLOSE,游标变量由接收方负责
显式游标一旦 OPEN,就必须显式 CLOSE,否则会累积导致 ORA-01000: maximum open cursors exceeded;游标变量没有“自己关自己”的义务——它被 OPEN ... FOR 后,资源归属权移交给了持有它的变量,通常由调用方(比如 Java 的 JDBC 或 Web 层)负责关闭。
容易踩的坑:
- 在存储过程中
OPEN rc FOR SELECT ...后直接RETURN rc,却忘了说明“此游标需由调用方关闭”——很多开发以为返回后就自动释放 - 显式游标在异常分支里漏写
CLOSE,尤其在EXCEPTION块中没补上,一出错就泄漏 - 用游标变量做循环处理(比如
FETCH rc INTO ...)时,误以为要像显式游标一样CLOSE rc,其实只要不重复 OPEN,FETCH 完自然结束,CLOSE 是调用方的事
FOR 循环写法不通用:显式游标支持,游标变量不支持直接 FOR 循环
FOR rec IN c LOOP ... END LOOP; 这种写法只适用于显式游标(包括参数化游标),因为编译器能在声明时推导出记录结构;游标变量无法直接用于 FOR 循环,否则报 PLS-00221: 'c' is not a procedure or is undefined。
替代方案只有两种:
- 用
FETCH ... INTO配合EXIT WHEN c%NOTFOUND手动循环(适合已知字段结构) - 用
BULK COLLECT INTO一次性取一批(如FETCH c BULK COLLECT INTO t_emp;),再遍历集合,性能更好但内存占用高
关键提醒:游标变量的 %FOUND、%NOTFOUND 等属性行为和显式游标一致,但 %ISOPEN 在未 OPEN 时为 FALSE,OPEN 后为 TRUE,这点常被忽略,导致空游标直接 FETCH 出错。


















