Spring Data JPA调用Oracle存储过程返回多参数报错求助
问题分析与解决方案
你的错误根源在于:Spring Data JPA的@Procedure注解直接返回Map时,不会自动将REF_CURSOR类型的输出参数转换为CustomerEntity实体列表,而是返回原始的JDBC ResultSet对象。这个对象内部关联了JDBC Statement、Connection等资源,Jackson序列化时会触发循环引用,导致报错。
Spring Data JPA支持调用带多个输出参数(包括REF_CURSOR)的Oracle存储过程,但需要调整实现方式,避免直接返回包含JDBC底层对象的Map。
正确实现步骤
1. 定义返回结果DTO
创建一个自定义DTO来封装所有输出参数,避免使用Map导致序列化问题:
public class CustResultDTO { private String localCode; private List<CustomerEntity> customers; // 构造器、getter、setter方法 public CustResultDTO(String localCode, List<CustomerEntity> customers) { this.localCode = localCode; this.customers = customers; } // 省略getter和setter }
2. 调整Repository结构
通过自定义Repository接口+实现类的方式,手动处理存储过程调用:
// 主Repository接口 @Repository public interface CustomerRepositoryExt extends JpaRepository<CustomerEntity, Long>, CustomerRepositoryExtCustom { } // 自定义方法接口 public interface CustomerRepositoryExtCustom { CustResultDTO getCust(String username); } // 实现类 @Repository public class CustomerRepositoryExtImpl implements CustomerRepositoryExtCustom { @PersistenceContext private EntityManager entityManager; @Override public CustResultDTO getCust(String username) { // 调用命名存储过程 StoredProcedureQuery query = entityManager.createNamedStoredProcedureQuery("Ent.getCust"); // 设置输入参数 query.setParameter("p_username", username); // 执行存储过程 query.execute(); // 获取普通OUT参数 String localCode = (String) query.getOutputParameterValue("o_local_code"); // 获取REF_CURSOR结果并转换为实体列表 List<CustomerEntity> customers = query.getResultList(); // 封装结果返回 return new CustResultDTO(localCode, customers); } }
3. 原实体类注解无需修改
你当前的@NamedStoredProcedureQuery配置是正确的,REF_CURSOR参数的type = Void.class符合Oracle的配置要求,不需要调整。
为什么原写法会报错?
原Repository方法返回Map<String, CustomerEntity>存在两个问题:
- REF_CURSOR对应的
o_result是结果集,不是单个CustomerEntity,类型不匹配; - Spring Data JPA的
@Procedure注解无法自动将REF_CURSOR的ResultSet转换为实体列表,返回的ResultSet包含JDBC底层资源(如Connection),Jackson序列化时会触发循环引用链,导致转换失败。
内容的提问来源于stack exchange,提问作者Quoc Thanh
相关产品推荐
相关产品推荐

