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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:22:26