Java调用Oracle Package过程时参数名无效,必须严格按位置索引(从1开始)匹配PL/SQL声明顺序,包名和过程名在{call ...}中须全大写,OUT参数须registerOutParameter后取值,REF CURSOR用OracleTypes.CURSOR注册并getObject转ResultSet,TABLE类型用createARRAY而非createStruct,OBJECT类型才用StructDescriptor构造STRUCT。

Java调用Oracle Package过程时,参数名和位置必须严格对应
Oracle Package里的过程(如 pkg_name.proc_name)在Java中调用,和裸过程没本质区别,但容易因包名、参数顺序或大小写踩坑。JDBC不识别“命名参数”,只认位置索引(从1开始),所以CALL pkg_name.proc_name(?, ?, ?)里问号的顺序必须和PL/SQL声明完全一致——哪怕存储过程中写了name IN VARCHAR2 DEFAULT 'abc',Java侧仍需为每个IN/OUT参数预留一个占位符。
常见错误现象:ORA-06550: wrong number or types of arguments,90%是因为参数个数对不上,或把OUT参数漏掉registerOutParameter();还有部分因包名拼错(比如写成PKG_NAME但实际是pkg_name,而数据库里类型名是大小写敏感的)。
- 包名和过程名在
{call ...}里必须全大写,除非建包时用了双引号强制小写(极少见,不建议) - 如果包在其他schema下,必须写全:{call SCHEMA_NAME.PKG_NAME.PROC_NAME(?, ?)}
- IN参数直接
setXxx();OUT参数必须先registerOutParameter(index, sqlType),再execute(),最后getXxx(index) - 对于
OUT SYS_REFCURSOR,sqlType用OracleTypes.CURSOR,取值用getObject()转ResultSet
传TABLE类型参数必须用createARRAY,不是createStruct
Package里过程若定义了自定义TABLE类型入参(如CREATE TYPE str_list AS TABLE OF VARCHAR2(100)),Java不能传List<string></string>或String[],也不能用createStruct——后者只适配OBJECT类型,强行用会报ORA-04043: type STR_LIST does not exist或invalid name pattern。
正确路径是拿到原生OracleConnection,调用createARRAY("STR_LIST", elements),其中elements必须是Object[],且不能为空(空集合传new Object[0])。
立即学习“Java免费学习笔记(深入)”;
-
typeName必须全大写、带schema前缀更稳(如"SCHEMA_NAME.STR_LIST") -
elements数组元素类型要和DB定义匹配:VARCHAR2 →String,NUMBER →BigDecimal或Integer,不能混用int[]或String[] - 驱动必须是ojdbc8+,低版本可能不支持某些集合类型
- 设置参数时用
setArray(index, array),不是setObject
调用含OBJECT类型参数的过程,才用createStruct
只有Package过程参数是自定义OBJECT(如CREATE TYPE person AS OBJECT(name VARCHAR2(50), age NUMBER)),才轮到createStruct出场。它需要先用StructDescriptor描述结构,再把字段值按顺序塞进Object[]构造实例。
典型错误是把TABLE和OBJECT搞混:看到“类型”就直觉用createStruct,结果驱动找不到对应OBJECT定义,抛出SQLException: invalid name pattern。
-
StructDescriptor的type name也必须全大写,且与DB中一致(如"PERSON") - 字段值数组
Object[]顺序必须和OBJECT定义字段顺序严格一致 - 嵌套OBJECT(如字段类型又是另一个OBJECT)需递归构造
STRUCT - 传入过程时仍用
setObject(index, struct),不是setStruct
参数超长(如CLOB)必须绕过setString走流式通道
Package过程若接收CLOB参数,别用setString()——ojdbc8对它有32KB隐式截断,会直接报Data size bigger than max size for this type,哪怕数据库字段和参数都声明为CLOB也没用。
唯一可靠方式是setCharacterStream(),把字符串包装成StringReader,并显式传入字符长度(不是字节长度)。
- 第三个参数必须是
longJson.length(),少一位都可能被截断 - 不要用
setClob(int, Reader),旧驱动里它会多一次内存拷贝,更慢更易OOM - 如果用MyBatis,得自定义
TypeHandler,重写setParameter方法强制走setCharacterStream - HTTP层也要同步放开限制(如Tomcat的
maxPostSize),否则前端根本发不过来


















