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

使用Hibernate JPA 2.1调用带IN参数列表与OUT游标Oracle存储过程报错

问题分析

你遇到的ORA-06550/PLS-00306错误,核心原因是Java代码传入的参数类型和Oracle存储过程期望的input_customer_ids自定义表类型不匹配。Spring Data JPA不会自动将Java的List<String>转换为Oracle的自定义TABLE类型,必须显式处理类型映射和转换。

解决方案

下面是两种可行的修复方式,你可以根据自己的代码风格选择:

方式一:直接修改存储过程调用代码

在调用存储过程时,手动将Java List转换为Oracle的ARRAY类型,并正确注册参数:

@PersistenceContext 
private EntityManager em;

public List<ClientAlertEntity> getAllClientAlertsList(List<String> customerIds) {
    StoredProcedureQuery findAllproc = em.createStoredProcedureQuery("STORED_P", ClientAlertEntity.class);
    
    // 注册输入参数:指定SQL类型为ARRAY,对应Oracle的自定义类型
    findAllproc.registerStoredProcedureParameter(
        "customer_ids", 
        Array.class, 
        ParameterMode.IN
    );
    
    // 注册输出游标参数
    findAllproc.registerStoredProcedureParameter(
        "prc", 
        void.class, 
        ParameterMode.REF_CURSOR
    );
    
    // 将Java List转换为Oracle ARRAY
    Session session = em.unwrap(Session.class);
    Connection conn = session.doReturningWork(connection -> connection);
    OracleConnection oracleConn = conn.unwrap(OracleConnection.class);
    // 注意这里的类型名要和Oracle中创建的INPUT_CUSTOMER_IDS完全一致(大小写敏感)
    Array customerIdArray = oracleConn.createARRAY("INPUT_CUSTOMER_IDS", customerIds.toArray());
    
    findAllproc.setParameter("customer_ids", customerIdArray);
    findAllproc.execute();
    
    @SuppressWarnings("unchecked")
    List<ClientAlertEntity> results = (List<ClientAlertEntity>) findAllproc.getResultList();
    return results;
}

方式二:使用@NamedStoredProcedureQuery注解(更简洁)

在你的ClientAlertEntity实体类上定义存储过程的映射,这样后续调用会更简洁:

@Entity
@NamedStoredProcedureQuery(
    name = "ClientAlertEntity.getAllByCustomerIds",
    procedureName = "STORED_P",
    resultClasses = ClientAlertEntity.class,
    parameters = {
        @StoredProcedureParameter(
            name = "customer_ids",
            type = Array.class,
            mode = ParameterMode.IN
        ),
        @StoredProcedureParameter(
            name = "prc",
            type = void.class,
            mode = ParameterMode.REF_CURSOR
        )
    }
)
public class ClientAlertEntity {
    // 你的实体类字段和注解...
}

然后修改调用方法:

public List<ClientAlertEntity> getAllClientAlertsList(List<String> customerIds) {
    StoredProcedureQuery query = em.createNamedStoredProcedureQuery("ClientAlertEntity.getAllByCustomerIds");
    
    // 转换List为Oracle ARRAY
    Session session = em.unwrap(Session.class);
    Connection conn = session.doReturningWork(connection -> connection);
    OracleConnection oracleConn = conn.unwrap(OracleConnection.class);
    Array customerIdArray = oracleConn.createARRAY("INPUT_CUSTOMER_IDS", customerIds.toArray());
    
    query.setParameter("customer_ids", customerIdArray);
    query.execute();
    
    return query.getResultList();
}

关键注意事项

  • 类型名称大小写:Oracle默认会将对象名称转换为大写,所以确保你在Java代码中使用的INPUT_CUSTOMER_IDS和Oracle中创建的类型名完全一致(如果创建时用了小写并加了双引号,那也要对应上)。
  • 权限问题:确保你的数据库用户有权限访问input_customer_ids类型和STORED_P存储过程。
  • 重复注册优化:如果多次调用这个存储过程,可以考虑在Spring配置类中初始化一次Oracle类型的注册,避免每次调用都重复执行转换逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:37:09