如何通过JDBI调用带自定义对象输出参数的Oracle存储过程?
问题:JDBI调用带自定义输出类型的Oracle存储过程报错
存储过程定义:
PROCEDURE customProcedure(in_val IN NUMBER, out_val OUT CUSTOM_OBJECT)
自定义对象类型:
CREATE TYPE CUSTOM_OBJECT AS OBJECT ( a NUMBER, b VARCHAR, .... )
Java尝试代码:
@SqlCall("call customProcedure(:input,:result)") @OutParameter(name="result", sqlType=Types.STRUCT) OutParameters callProcedure(@Bind("input") Long input);
遇到的异常情况:
- 输出参数绑定阶段触发
java.sql.SQLException: Invalid argument(s) in call,调试发现是OracleCallableStatement注册STRUCT类型时传入null变量导致 - 更换输出类型后,要么出现
java.sql.SQLException: Invalid column type: [所选sqlType的整数值],要么触发oracle.jdbc.OracleDatabaseException: ORA-06553: PLS-306: wrong number or types of arguments in call to 'customProcedure' - 手动通过
jdbi.handle.createCall("...").registerOutParameter(...)调用,结果一致
询问如何正确调用这类存储过程?
解决方案
1. 定义对应自定义类型的Java实体类
首先创建与CUSTOM_OBJECT字段一一对应的Java类:
public class CustomObject { private Long a; private String b; // 补充其他字段、全参/无参构造方法、getter/setter }
2. 用Oracle特定类型注册输出参数
不能直接使用Types.STRUCT,需要指定Oracle自定义类型的名称,同时使用Oracle JDBC专属的OracleTypes.STRUCT类型代码:
注解方式
直接修改SQL调用注解,指定类型名称并返回目标实体类:
import oracle.jdbc.OracleTypes; import org.jdbi.v3.sqlobject.customizer.OutParameter; import org.jdbi.v3.sqlobject.statement.SqlCall; @SqlCall("{call customProcedure(:input, :result)}") @OutParameter(name = "result", sqlType = OracleTypes.STRUCT, typeName = "CUSTOM_OBJECT") CustomObject callProcedure(@Bind("input") Long input);
手动调用方式
如果注解方式不生效,手动调用时明确指定类型名称:
try (Handle handle = jdbi.open()) { CustomObject result = handle.createCall("{call customProcedure(?, ?)}") .bind(0, 123L) .registerOutParameter(1, OracleTypes.STRUCT, "CUSTOM_OBJECT") .invoke() .getObject(1, CustomObject.class); }
3. 注册STRUCT到Java类的映射器
需要告诉JDBI如何将Oracle的STRUCT对象转换为自定义Java类,注册一个ColumnMapper:
jdbi.registerColumnMapper(CustomObject.class, (rs, col, ctx) -> { Struct struct = rs.getObject(col, Struct.class); if (struct == null) { return null; } Object[] attributes = struct.getAttributes(); CustomObject obj = new CustomObject(); obj.setA((Long) attributes[0]); obj.setB((String) attributes[1]); // 为其他字段赋值 return obj; });
4. 关键注意事项
- 确保Oracle JDBC驱动版本与数据库版本兼容,避免类型处理的兼容性问题
- 自定义类型名称
"CUSTOM_OBJECT"要与数据库中定义的完全一致(Oracle默认区分大小写,通常为大写) - JDBI 3.x及以上版本对自定义类型支持更完善,建议使用对应版本的API
内容的提问来源于stack exchange,提问作者Mewster
相关产品推荐
相关产品推荐

