mybatis或jdbc调用oracle存储过程报pls-00306/ora-06550,90%因参数类型声明缺失或错配:必须显式指定jdbctype(如varchar)和mode(in/out),不可依赖默认推断,否则oracle驱动将null或字符串映射为不被接受的other类型。

MyBatis 或原生 JDBC 调用 Oracle 存储过程时抛 PLS-00306 或 ORA-06550,90% 是参数类型声明缺失或错配,不是 SQL 写错,也不是存储过程本身有问题。
必须显式写死 jdbcType 和 mode,不能依赖默认推断
Oracle JDBC 驱动对 NULL 字符串、空字符串、动态字段一律映射为 JdbcType.OTHER,而 Oracle PL/SQL 不接受 OTHER 作为任何参数类型。哪怕 Java 传的是 String,驱动也不会自动认作 VARCHAR2。
-
#{paramName,jdbcType=VARCHAR,mode=IN}:所有字符串类IN参数都应加,尤其来自Map或可为空的字段 -
#{outParam,mode=OUT,jdbcType=VARCHAR}:OUT参数缺mode或jdbcType任一者,绑定直接失败 - 即使参数值确定非
null,也建议写全——上线后数据内容变化(比如某字段突然存了空值)就会触发报错 -
jdbcTypeForNull=NULL全局配置对存储过程无效,因为 CallableStatement 不走通用参数解析路径
数组/自定义类型参数要转成 oracle.sql.ARRAY,不能直接传 List
Oracle 存储过程若声明了 IN TAB_CUSTOMER 这类自定义集合类型,Java 侧传 List<customer></customer> 会报“参数个数或类型错误”,因为 JDBC 无法自动把 Java 集合转成 Oracle 的 ARRAY 对象。
- 必须用
ArrayDescriptor.createDescriptor("TAB_CUSTOMER", conn)创建描述符 - 每个元素要封装为
STRUCT,字段顺序、类型、长度需与TYP_CUSTOMER定义严格一致 -
STRUCT构造时,DATE字段要用oracle.sql.DATE包装,不能用java.sql.Date - 别用
setObject(i, list, Types.ARRAY)—— 驱动不认识你的自定义类型名,会 fallback 到OTHER
超长字符串传 CLOB 必须绕过 setString()
用 setString() 传超过 32KB 的字符串给 IN CLOB 参数,JDBC 驱动会自己拦截并抛 Data size bigger than max size for this type,这不是 Oracle 报错,是 ojdbc8 内部按 VARCHAR2 路径做的缓冲校验。
- 必须改用
setCharacterStream(int, Reader, long),第三个参数传字符数(不是字节数) - MyBatis 场景下需自定义
TypeHandler,重写setParameter(),强制调用setCharacterStream - 不要用
setClob(int, Reader):旧版 ojdbc 可能触发额外内存拷贝,性能更差 - 超 100MB 大文本需分段:先插
EMPTY_CLOB()占位,再用DBMS_LOB.WRITEAPPEND分批写入(每批 ≤32KB),且事务不能提交
ORA-06550 错误里的 line 1, column 7 指的是什么
这个位置不是你 Java 代码行号,而是 JDBC 驱动生成的匿名 PL/SQL 块内部偏移,例如 { call p_test(?, ?, ?) } 中第一个 ? 的位置。它只说明参数绑定失败发生在第几个占位符,不反映存储过程定义问题。
- 真正要看的是错误附带的子错误,比如
PLS-00306: wrong number or types of arguments in call to 'p_test' - 检查点优先级:参数个数是否匹配 → 参数物理顺序是否和存储过程定义一致 → 每个参数的
mode和jdbcType是否都写了 →OUT参数是否在execute()前注册了registerOutParameter() - Oracle 存储过程中参数名大小写不敏感,但 MyBatis 的
#{xxx}必须和 Java 对象字段名或 Map key 完全一致(区分大小写)
最容易被忽略的是:OUT 参数在 MyBatis XML 里漏写 mode=OUT,或者原生 JDBC 忘了调 registerOutParameter() —— 这会导致驱动根本不去分配返回缓冲区,后续取值必然失败,且错误信息极不直观。











