Oracle存储过程调用参数类型不匹配,根本原因是MyBatis对null或未标注类型的字符串参数默认映射为JdbcType.OTHER,而Oracle JDBC驱动严格要求类型精确匹配(如VARCHAR2),导致PLS-00306或ORA-06550错误;必须显式声明jdbcType和mode,尤其OUT参数缺一不可。
必须显式声明 jdbctype,否则 oracle 会把 null 或字符串参数误判为 jdbctype.other,直接报错
为什么 Oracle 存储过程调用总卡在参数类型不匹配
MyBatis 默认对 null 值或未标注类型的字符串参数,在 Oracle 场景下统一映射为 JdbcType.OTHER。而 Oracle 存储过程签名严格要求类型精确匹配(比如 IN VARCHAR2),OTHER 不被接受,就会抛出 PLS-00306 或 ORA-06550 类错误。
这不是 MyBatis 的 bug,是 Oracle JDBC 驱动的强类型约束所致——MySQL 等数据库没这问题,所以容易忽略。
在 #{...} 中强制指定 jdbctype=VARCHAR 的写法
所有 IN/INOUT 类型的字符串参数,只要不确定是否为空、或来自动态拼接字段,都应显式加 jdbcType=VARCHAR;OUT 参数则必须配 mode=OUT + jdbcType。
-
#{test1,jdbcType=VARCHAR,mode=IN}—— 明确告诉 MyBatis:这是输入字符串,别猜 -
#{testresult1,mode=OUT,jdbcType=VARCHAR}—— OUT 参数缺一不可,否则驱动无法绑定返回值 - 即使 Java 侧传的是
String,也不代表 Oracle 侧自动认作VARCHAR2;JDBC 层需要明确指令
示例片段:
{ call YDJW_XD.p_check_fjdcxr_dccf (
#{test1,jdbcType=VARCHAR,mode=IN},
#{test2,jdbcType=VARCHAR,mode=IN},
#{testresult1,mode=OUT,jdbcType=VARCHAR}
) }
全局配置 jdbcTypeForNull=NULL 不足以覆盖存储过程场景
虽然在 里加 能缓解 INSERT/UPDATE 的 null 问题,但它对存储过程无效——因为存储过程参数绑定走的是 CallableStatement 路径,不走通用参数解析逻辑。
所以:
- 普通 SQL(
)可依赖全局配置 + 局部jdbcType=NULL - 存储过程(
statementType="CALLABLE")必须每个参数都手动写jdbcType和mode - 哪怕参数值非 null,也建议写全,避免上线后因数据内容变化突然失败
容易漏掉的三个关键点
实际调试中最常栽跟头的地方:
- Oracle 存储过程的参数名大小写不敏感,但 MyBatis 的
#{xxx}必须和 Java 对象字段名或 Map key 完全一致(区分大小写) -
mode=IN参数如果传了null,仍需配合jdbcType=VARCHAR,光靠jdbcTypeForNull不生效 - OUT 参数对应的 Java 对象字段,必须是可写(public setter 或 public field),否则结果值无法回填,但错误不会立刻抛出,而是字段保持 null 或默认值
真正要命的不是报错,是静默失败——看着调用成功,但 OUT 返回值没进对象里。











