使用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
相关产品推荐
相关产品推荐

