Java调用Oracle Package中存储过程必须显式写全包名,否则报ORA-06576;正确格式为{call schema.package.proc(?)},包名和过程名一般全大写,IN/OUT参数顺序须与声明严格一致,游标输出必须注册OracleTypes.CURSOR。

Java调用Oracle Package中存储过程必须显式写全包名
不写包名会直接报 ORA-06576: not a valid procedure or function name。Oracle对Package内过程的解析是强命名的,{call my_proc(?)} 这种写法只适用于独立过程;调用包内过程必须写成 {call my_package.my_proc(?)} 。
常见错误是把包名当路径或前缀忽略,比如误写为 {call my_proc(?)} 或 {call "MY_PACKAGE"."MY_PROC"(?)}(双引号在JDBC里反而触发大小写敏感匹配,而实际类型名通常为大写但驱动不强制要求引号)。
- 包名和过程名都按数据库定义的大小写写,一般全大写更稳:
{call EMP_PKG.INSERT_EMPLOYEE(?, ?)} - 如果包在其他 schema 下,必须带 schema 前缀:
{call HR.EMP_PKG.INSERT_EMPLOYEE(?, ?)} - MyBatis 中调用需在 SQL 里显式拼包名,不能只靠
statementType="CALLABLE"自动识别
IN/OUT 参数顺序和 registerOutParameter 必须严格对应声明顺序
Package 中过程参数顺序是 PL/SQL 层面固定的,Java 侧 setXXX() 和 registerOutParameter() 的索引(从 1 开始)必须与存储过程定义中参数的位置完全一致,错一位就取不到值或报 Invalid column index。
例如过程定义为 PROCEDURE calc_salary(emp_id IN NUMBER, bonus OUT NUMBER, msg OUT VARCHAR2),那么 Java 中:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
cstmt.setInt(1, 123)→ 对应第一个参数emp_id -
cstmt.registerOutParameter(2, OracleTypes.NUMBER)→ 对应第二个参数bonus -
cstmt.registerOutParameter(3, OracleTypes.VARCHAR)→ 对应第三个参数msg - 执行后
cstmt.getInt(2)和cstmt.getString(3)才能拿到正确结果
传 TABLE 类型参数时,createARRAY 的 type name 必须带 schema 或全大写
Package 本身不改变自定义类型的归属,TABLE 类型(如 CREATE TYPE STR_LIST AS TABLE OF VARCHAR2(100))仍属于 schema 级对象。即使该类型和 package 同 schema,createARRAY("STR_LIST", elements) 也可能失败,报 ORA-04043: type STR_LIST does not exist。
根本原因是 JDBC 驱动查 type 时走的是当前连接用户 schema,若类型在另一个 schema 下(比如 DBA 定义的公共类型),不写 schema 就找不到。
- 安全写法是显式带上 schema:
((OracleConnection) conn).createARRAY("HR.STR_LIST", elements) - 如果类型确实在当前用户下,可试
"STR_LIST",但建议统一用大写,避免大小写映射问题 -
elements必须是Object[],哪怕内容全是String,也不能传String[] - 空数组要传
new Object[0],传null会触发NullPointerException在createARRAY内部
调用带 REF CURSOR 输出的 Package 过程,registerOutParameter 类型必须是 OracleTypes.CURSOR
Package 中返回游标的典型写法是 PROCEDURE get_employees(p_deptno IN NUMBER, p_cursor OUT SYS_REFCURSOR)。Java 侧若用 Types.OTHER 或漏掉 registerOutParameter,会报 Invalid column type 或取出来是 null。
关键点在于:REF CURSOR 不是普通类型,必须用 Oracle 特定常量注册,且后续要用 getObject() 转成 ResultSet。
-
cstmt.registerOutParameter(2, OracleTypes.CURSOR)—— 第二个参数是游标 cstmt.execute()-
ResultSet rs = (ResultSet) cstmt.getObject(2)—— 注意不是getResultSet() - 不要用
setNull(2, OracleTypes.CURSOR),游标输出参数不能设 null 输入值
最容易被忽略的是:如果 Package 过程里游标是通过 OPEN p_cursor FOR SELECT ... 打开的,那它依赖当前事务上下文;Java 端必须在同一个 connection 上执行,且不能提前 commit 或 close connection,否则游标失效。

















