必须用#{}传参,但游标OUT参数不能用#{}直接接收;需声明jdbcType=ORACLECURSOR、mode=OUT并绑定resultMap,否则报Invalid column type: 1111。

MyBatis调用Oracle存储过程必须用#{}还是${}?
必须用#{},但仅用于传参;游标本身不能用#{}接收。Oracle存储过程的OUT SYS_REFCURSOR参数必须声明为jdbcType=ORACLECURSOR,且只能通过Map或自定义resultMap映射到Java对象——直接写#{cursor}会报Invalid column type: 1111错误。
-
#{}用于输入参数(如#{userId,jdbcType=INTEGER}),类型安全 -
${}绝对禁用在游标场景,它会做字符串拼接,导致SQL语法错误或注入风险 - MyBatis不支持把
OUT游标直接映射成List<user></user>,必须走resultMap或Map中转
XML里怎么声明SYS_REFCURSOR输出参数?
在<select></select>标签中用statementType="CALLABLE",并通过<parametermap></parametermap>(已过时)或更推荐的<parametermode></parametermode>方式声明游标参数。注意:JDBC驱动版本影响写法,Oracle 12c+建议用jdbcType=ORACLECURSOR而非OTHER。
- 必须加
statementType="CALLABLE",否则MyBatis按普通查询处理,无法识别OUT参数 - 游标参数要显式设
mode="OUT"和jdbcType="ORACLECURSOR",例如:<param property="userCursor" mode="OUT" jdbctype="ORACLECURSOR" resultmap="userResultMap"> - 对应Java方法参数需是
Map<string object></string>或带@Param注解的POJO,不能是简单类型
Java代码里怎么拿到游标结果?
调用后,游标结果已自动填充进你传入的Map或POJO的对应字段,不需要手动ResultSet.next()。但要注意:这个Map必须是可变的(不能是Collections.emptyMap()),且字段名严格匹配XML中property值。
- 示例调用:
Map<string object> params = new HashMap(); params.put("userId", 123); mapper.getUserList(params); List<user> users = (List<user>) params.get("userCursor");</user></user></string> - 如果用POJO,确保该POJO有
setUserCursor(List<user>)</user>或setUserCursor(ResultSet)(后者不推荐,耦合JDBC) - 别忘了在Oracle存储过程中真正打开游标:
OPEN user_cursor FOR SELECT * FROM users WHERE id = p_id;
常见报错ORA-06550 / PLS-00306怎么快速定位?
这基本是存储过程签名和MyBatis参数声明不一致导致的。不是Java代码问题,而是PL/SQL端和XML端“对不上号”。
立即学习“Java免费学习笔记(深入)”;
- 检查存储过程参数顺序、名称、大小写(Oracle默认大写,MyBatis XML里
property也要大写或按实际定义) - 确认JDBC URL含
oracle.jdbc.mapDateToTimestamp=false(避免DATE类型隐式转换干扰) - 用
SELECT * FROM USER_PROCEDURES WHERE OBJECT_NAME = 'YOUR_PROC_NAME'查真实参数定义 - MyBatis日志开到DEBUG,看最终生成的JDBC CallableStatement是否含
{call ...}及占位符数量是否匹配
游标映射不是黑盒,关键在两端声明一致;最容易被忽略的是Oracle侧没真正OPEN游标,或者Java侧用了不可变容器接收结果。


















