ORA-08103错误源于MyBatis未及时消费Oracle游标,导致连接关闭后游标被释放;须在XML中同时配置jdbcType=CURSOR、javaType=java.sql.ResultSet和resultMap,且三者缺一不可。

ORA-08103:游标对象不再存在
这个错误不是数据库表被删了,而是 MyBatis 拿到 OracleResultSetImpl 后没及时消费,连接关闭或事务提交后游标句柄被 Oracle 自动释放。常见于没用 resultMap 映射、没配 javaType=ResultSet、或调用后直接返回未遍历的游标对象。
典型表现是:Java 代码里 map.get("cursorKey") 拿到一个非 null 对象,但一转成 List 就抛 ORA-08103;或者在 Service 层 return 前没做任何处理,等 Controller 想用时游标已失效。
- 必须确保 XML 中
jdbcType=CURSOR同时声明javaType=java.sql.ResultSet和resultMap,三者缺一不可 - 不要把游标结果存进 Map 后就返回——MyBatis 不会自动遍历它,得手动调用
query.get("cursorKey")并立即处理 - 若用
ResultHandler流式处理,必须保证 handler 在同一事务上下文内执行,且不能跨线程或延迟调用
MyBatis 解析 CURSOR 参数失败,返回原始 ResultSetImpl
MyBatis 看到 jdbcType=CURSOR 但没配 resultMap 或 javaType,就会跳过类型转换逻辑,直接把底层 OracleResultSetImpl 塞进 Map。后续代码强转 List 或 Map 必然 ClassCastException。
-
resultMap的 id 必须和 XML 中resultMap=xxx完全一致,大小写敏感 -
javaType必须显式写成java.sql.ResultSet,不能省略或写成ResultSet - 如果用了泛型实体类(如
List),resultMap的type要对应类全限定名,不能只写Product
存储过程里没正确打开游标,或游标变量名不匹配
Oracle 存储过程中游标参数必须是 OUT SYS_REFCURSOR 类型,并且 OPEN 语句里的变量名要和 Java 侧传入的占位符名完全一致(包括大小写)。MyBatis 不按名字绑定,但驱动依赖名字匹配来关联结果集。
- PL/SQL 里定义为
p_cur OUT SYS_REFCURSOR,XML 中就得用#{p_cur, mode=OUT, jdbcType=CURSOR, ...} - 别写成
#{cur, ...}或#{PCUR, ...},哪怕只是大小写差异也会导致游标没被识别 - 确保
OPEN p_cur FOR SELECT ...在存储过程逻辑中真实执行——比如有 IF 分支没覆盖到,游标可能根本没打开
没设 size 或 registerOutParameter 导致驱动无法识别游标类型
某些老版本 Oracle JDBC 驱动(如 ojdbc6)对 CURSOR 类型要求显式注册,否则当成普通 OUT 参数处理,最终返回 null 或非法对象。
- MyBatis 底层调用
CallableStatement.registerOutParameter(index, Types.OTHER),但部分驱动需要的是OracleTypes.CURSOR - 可在 Mapper XML 中加
jdbcType=CURSOR后追加numericScale="1"试探兼容性(极少数场景有用) - 更稳妥的做法是升级到 ojdbc8+,并确认项目中没混用多个版本的 Oracle 驱动 jar
游标问题最麻烦的地方不在写法,而在于“看起来成功了但实际没生效”——日志里没报错、Map 里有值、甚至 IDE 调试能看到对象地址,可一取数据就崩。务必在 DAO 层拿到游标后立刻遍历一次,哪怕只取一条,才能暴露绑定是否真成功。











