You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ojdbc8 19.3下CallableStatement命名绑定调用函数报PLS-00306错误

问题背景

Java 8项目中将Oracle JDBC驱动从ojdbc6升级至ojdbc8 19.3.0.0版本后,调用带返回值的PL/SQL函数时抛出如下异常:

Caused by: java.sql.SQLException: ORA-06550: line 1, column 18:
PLS-00306: wrong number or types of arguments in call to 'MAKEWORK'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

触发场景

执行以下命名绑定方式的函数调用代码时触发异常:

try (CallableStatement cs = con.prepareCall("{call :result := CORE.PKG.makeWork(arg1=>:arg1, arg2=>:arg2)}")) {
    cs.setString("arg1", javaArg1);
    cs.setInt("arg2", javaArg2);
    cs.registerOutParameter("result", Types.ARRAY, CommonTypeNameConstant.T_TABLE_OF_NUMBERS_TYPE);
    cs.execute();
    Array result = (Array) cs.getObject("result");
}

该问题仅存在于函数调用场景:如果CORE.PKG.makeWork是存储过程,相同的命名绑定写法可正常运行:

try (CallableStatement cs = con.prepareCall("{call CORE.PKG.makeWork(arg1=>:arg1, arg2=>:arg2)}")) {
    cs.setString("arg1", javaArg1);
    cs.setInt("arg2", javaArg2);
    cs.execute();
}

已验证的临时方案

将命名绑定改为顺序绑定可解决问题,但改造成本较高:

try (CallableStatement cs = con.prepareCall("{? = call CORE.PKG.makeWork(arg1=>?, arg2=>?)}")) {
    cs.registerOutParameter(1, Types.ARRAY, CommonTypeNameConstant.T_TABLE_OF_NUMBERS_TYPE);
    cs.setObject(2, javaArg1);
    cs.setObject(3, javaArg2);
    cs.execute();
    Array result = (Array) cs.getObject(1);
}

该方案存在两个明显弊端:

  • 顺序绑定容易出现参数顺序编写错误,提升代码bug率
  • 项目中存在大量存量命名绑定脚本,全量改写人力成本高

问题根因

出现该问题的核心原因是ojdbc8 19.3.0.0版本的参数解析逻辑做了收紧调整:

  1. JDBC规范中定义的存储过程调用标准语法为{call 过程名(参数列表)},函数调用标准语法为{? = call 函数名(参数列表)}。之前使用的{call :result := 函数名(...)}是Oracle旧驱动兼容的非标准PL/SQL块写法,不属于JDBC标准调用语法范畴。
  2. ojdbc6及更早版本对非标准写法做了宽松兼容:会自动识别赋值符:=左侧的:result为命名绑定的输出参数,和参数列表内的命名占位符统一做名称映射,因此代码可正常运行。
  3. ojdbc8 19.3.0.0版本重构了CallableStatement的参数解析逻辑,默认仅在JDBC标准调用语法下支持命名参数绑定:当检测到非标准的{call ... := ...}写法时,驱动会把大括号内的全部内容当做普通匿名PL/SQL块处理,不会自动识别块内的:result、:arg1这类命名占位符做参数映射,最终传给数据库的PL/SQL块中占位符未被正确绑定参数类型,数据库侧就会抛出PLS-00306参数数量/类型不匹配的错误。
  4. 存储过程调用场景下使用的是{call 过程名(...)}的JDBC标准语法,驱动的命名参数解析逻辑可正常生效,因此不会报错。

低改造成本兼容方案

不需要全量改写为顺序绑定,可选择以下两种方案保留命名绑定写法:

  • 方案一:开启驱动兼容开关。在JDBC连接配置中添加连接属性oracle.jdbc.plsqlNamedParameters=true,开启后驱动会恢复ojdbc6版本对非标准语法、匿名PL/SQL块下的命名参数解析逻辑,原有业务代码不需要做任何改动即可正常运行。
  • 方案二:微调SQL为标准语法。将所有函数调用的SQL从非标准的{call :返回值变量 := 函数名(参数列表)}调整为JDBC标准格式{? = call 函数名(参数列表)},参数列表内部的命名绑定写法(arg1=>:arg1、arg2=>:arg2)完全不需要改动,仅需将返回值的注册、取值逻辑从原命名参数改为获取第1位参数即可,改造量远低于全量改为顺序绑定。

内容的提问来源于stack exchange,提问作者Robert Ishmukhametov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:27:16