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

如何在Java(Hibernate)中调用带自定义类型参数的Oracle存储过程

解决Java+Hibernate调用Oracle包中PL/SQL自定义类型存储过程的问题

针对你遇到的Oracle包内REG_RET记录类型、TAB_RET关联数组类型的参数传递问题,直接利用Oracle JDBC驱动的扩展API结合Hibernate即可解决,具体步骤如下:

1. 准备Java实体类映射PL/SQL记录类型

先创建对应REG_RET的Java类,字段类型与Oracle定义严格匹配:

import java.math.BigDecimal;

public class RegRet {
    private Integer group;
    private Integer market;
    private BigDecimal amount;

    public RegRet(Integer group, Integer market, BigDecimal amount) {
        this.group = group;
        this.market = market;
        this.amount = amount;
    }

    // 生成getter方法
    public Integer getGroup() { return group; }
    public Integer getMarket() { return market; }
    public BigDecimal getAmount() { return amount; }
}

2. 结合Hibernate与Oracle JDBC扩展API调用存储过程

Hibernate的StoredProcedureQuery可以直接unwrap到Oracle专属的OracleCallableStatement,利用其setPlsqlIndexTable方法处理PL/SQL关联数组:

import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleConnection;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.math.BigDecimal;

// 1. 构造要传入的记录列表
List<RegRet> retList = new ArrayList<>();
retList.add(new RegRet(1, 110, new BigDecimal("500")));
retList.add(new RegRet(1, 95, new BigDecimal("300")));

// 2. 初始化Hibernate存储过程查询
EntityManager em = // 从上下文获取你的EntityManager
StoredProcedureQuery query = em.createStoredProcedureQuery("PAC_EXAMPLE.P_CREATE_ELEMENT");

// 3. 注册所有参数
query.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
query.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
query.registerStoredProcedureParameter(3, Object.class, ParameterMode.IN); // 占位,后续用JDBC处理
query.registerStoredProcedureParameter(4, Integer.class, ParameterMode.OUT);

// 4. 设置普通输入参数
query.setParameter(1, "JHON");
query.setParameter(2, "JHON R");

// 5. 转换为Oracle专属CallableStatement
OracleCallableStatement oracleCs = query.unwrap(OracleCallableStatement.class);

try {
    // 6. 获取Oracle连接,构造STRUCT数组(对应REG_RET记录)
    Connection conn = oracleCs.getConnection();
    OracleConnection oracleConn = conn.unwrap(OracleConnection.class);
    StructDescriptor structDesc = StructDescriptor.createDescriptor("PAC_EXAMPLE.REG_RET", oracleConn);
    
    STRUCT[] structArray = new STRUCT[retList.size()];
    for (int i = 0; i < retList.size(); i++) {
        RegRet ret = retList.get(i);
        Object[] attributes = new Object[]{
                ret.getGroup(),
                ret.getMarket(),
                ret.getAmount()
        };
        structArray[i] = new STRUCT(structDesc, oracleConn, attributes);
    }

    // 7. 设置PL/SQL关联数组参数
    oracleCs.setPlsqlIndexTable(
            3,          // 参数索引(第三个参数)
            structArray,// 要传入的STRUCT数组
            structArray.length, // 数组长度
            structArray.length, // 最大元素数
            oracle.jdbc.OracleTypes.STRUCT, // 元素类型
            "PAC_EXAMPLE.REG_RET" // 元素对应的PL/SQL类型名称
    );

    // 8. 执行存储过程并获取输出参数
    oracleCs.execute();
    Integer outId = oracleCs.getInt(4);
    System.out.println("output: " + outId);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        oracleCs.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

关键注意事项

  • 必须引入Oracle官方JDBC驱动(如ojdbc8),setPlsqlIndexTable是Oracle专属API;
  • 确保数据库用户拥有PAC_EXAMPLE包的执行权限;
  • 包定义中存在笔误:PROCEDURE的pa_ret参数类型应为TAB_RET(而非tab_retenciones),END语句应改为END PAC_EXAMPLE;,否则存储过程无法正常编译。

内容的提问来源于stack exchange,提问作者rolo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:47:26