调用含VARRAY对象的Oracle存储过程时遇ORA-06550/PLS-00306错误(MyBatis)
MyBatis调用Oracle存储过程(含VARRAY参数)的ORA-06550/PLS-00306错误排查
核心错误原因
ORA-06550与PLS-00306本质是参数绑定不匹配,在涉及Oracle自定义VARRAY类型时,大概率是MyBatis未正确识别集合类型的映射规则,而非参数名称/顺序问题。
逐步排查与修复方案
1. 注册VARRAY类型处理器
Oracle的VARRAY属于自定义集合类型,MyBatis无法自动映射,必须显式实现并注册类型处理器:
- 编写类型处理器(继承
BaseTypeHandler):public class OracleVarrayTypeHandler extends BaseTypeHandler<List<String>> { // 替换为你的VARRAY完整类型名(含schema) private static final String VARRAY_FULL_NAME = "SCOTT.STRING_VARRAY"; @Override public void setNonNullParameter(PreparedStatement ps, int idx, List<String> param, JdbcType jdbcType) throws SQLException { Connection conn = ps.getConnection(); // 按Oracle类型创建数组 Array oracleArray = conn.createArrayOf(VARRAY_FULL_NAME, param.toArray()); ps.setArray(idx, oracleArray); } @Override public List<String> getNullableResult(ResultSet rs, String colName) throws SQLException { return parseOracleArray(rs.getArray(colName)); } @Override public List<String> getNullableResult(ResultSet rs, int colIdx) throws SQLException { return parseOracleArray(rs.getArray(colIdx)); } @Override public List<String> getNullableResult(CallableStatement cs, int paramIdx) throws SQLException { return parseOracleArray(cs.getArray(paramIdx)); } // 解析Oracle Array为Java List private List<String> parseOracleArray(Array array) throws SQLException { if (array == null) return null; Object[] elements = (Object[]) array.getArray(); return Arrays.asList(Arrays.copyOf(elements, elements.length, String[].class)); } } - 在MyBatis配置文件中注册处理器:
<configuration> <typeHandlers> <typeHandler handler="com.yourpackage.OracleVarrayTypeHandler" javaType="java.util.List" jdbcType="ARRAY"/> </typeHandlers> </configuration>
2. 修正MyBatis映射文件参数配置
确保OUT参数的mode、jdbcType、typeHandler配置完整:
<select id="callVarrayProc" statementType="CALLABLE"> {call SCOTT.PROC_WITH_VARRAY( #{inputParam, mode=IN, jdbcType=VARCHAR}, #{outputVarray, mode=OUT, jdbcType=ARRAY, typeHandler=com.yourpackage.OracleVarrayTypeHandler}, #{outputCode, mode=OUT, jdbcType=NUMBER} )} </select>
注意:必须指定VARRAY的完整Oracle类型名(含schema),否则数据库无法定位类型。
3. 验证Java与Oracle类型匹配
- 若Oracle VARRAY定义为
VARRAY(100) OF VARCHAR2(50),Java端用List<String>接收即可; - 若VARRAY是自定义OBJECT类型的集合,需为OBJECT创建对应Java实体类,并在类型处理器中实现实体与Oracle OBJECT的转换逻辑。
4. 排除存储过程本身问题
先在数据库端直接调用存储过程,确认过程本身无错:
DECLARE v_input VARCHAR2(50) := 'test'; v_varray SCOTT.STRING_VARRAY; v_code NUMBER; BEGIN SCOTT.PROC_WITH_VARRAY(v_input, v_varray, v_code); DBMS_OUTPUT.PUT_LINE('输出码:' || v_code); -- 遍历VARRAY验证结果 FOR i IN 1..v_varray.COUNT LOOP DBMS_OUTPUT.PUT_LINE('元素' || i || ':' || v_varray(i)); END LOOP; END; /
如果数据库端调用报错,优先修复存储过程定义;如果正常,问题必然在MyBatis的映射配置上。
5. 检查参数绑定细节
- Oracle存储过程对参数名称大小写敏感,确保MyBatis中
@Param注解的名称与存储过程参数名完全一致; - 若名称绑定仍有问题,可尝试改用位置绑定(MyBatis支持
#{}按位置索引绑定,但需注意参数顺序)。
高频错误点总结
- 未注册VARRAY类型处理器,MyBatis无法解析Oracle集合类型;
- 映射文件中OUT参数未指定
jdbcType=ARRAY或typeHandler路径错误; - VARRAY类型名未带schema,数据库找不到自定义类型;
- Java接收类型与VARRAY元素类型不匹配(如Oracle用NUMBER,Java用String)。
内容的提问来源于stack exchange,提问作者Emmanuele Guerriero
相关产品推荐
相关产品推荐

