使用 Spring JPA 调用存储过程

Posted

技术标签:

【中文标题】使用 Spring JPA 调用存储过程【英文标题】:Stored procedure call with Spring JPA 【发布时间】:2021-03-15 09:36:30 【问题描述】:

我需要使用 JPA 调用存储过程。存储过程对多个表进行操作,并从这些表中返回一些列。

尝试使用@Procedure 似乎不起作用,在这种情况下始终找不到存储过程。

使用本机查询直接调用过程是成功的,但是使用这种方法,我需要将返回的结果映射到一个对象的列表。

我在存储库中的实现如下所示,

@Query(value = "EXECUTE dbs.multitable_Test :inputObj", nativeQuery = true)
List<sp> multitable_Test(@Param("inputObj")String inputObj);

存储过程返回的结果需要映射到sp类。

当我们在单个结果集中有多个表响应时,如何实现这一点?

已经尝试使用attributeConvert from this link,仍然出现以下异常。

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type

对此的任何帮助表示赞赏。

【问题讨论】:

我认为存储过程不适合 JPA。 @duffymo 没有任何解决方法支持这个吗? 我不知道。 JPA 是关系数据库之上的一层,它允许假装您只处理对象。存储过程不适合该模型。您已经在使用 Spring。只需使用 Spring JDBC 模板来管理它。 【参考方案1】:

首先,这不是过程的真正用例。过程是为了修改数据库上的数据而没有任何返回值,那么你可以使用:

@Procedure(procedureName = "procedure_name")
void procedure(); // notice void

您应该使用function 和create function 语法。函数可以修改数据并返回结果。

其次,如果您想将其映射到某个类,我看到了两种解决方案(使用EntityManager):

    使用ResultTransformer

    entityManager.createNativeQuery(
        "select * from function_name(:parameter)"
    )
        .setParameter("parameter", parameter)
        .unwrap(org.hibernate.query.NativeQuery.class)
        .setResultTransformer(new ResultTransformer() 
            @Override
            public Object transformTuple(Object[] tuple, String[] aliases) 
                return new Sp(tuple[0]);
            
    
            @Override
            public List transformList(List collection) 
                return collection;
            
    
        )
        .getResultList();
    

    请注意,ResultTransformer 已被弃用,但功能如此强大,除非有合理的替代品,否则不会将其删除,请参阅 hibernate 开发人员的the note。

    使用ResultSetMapping。在实体上放置适当的注释:

    @SqlResultSetMapping(
        name = "sp_mapping",
        classes = @ConstructorResult(
            targetClass = Sp.class,
            columns = 
                @ColumnResult(name = "attribute", type = Long.class)
            )
    )
    

    并使用映射作为参数调用函数:

    entityManager.createNativeQuery(
        "select * " +
        "from function_name(:parameter);",
        "sp_mapping"
    )
        .setParameter("parameter", parameter)
        .getResultList();
    

【讨论】:

以上是关于使用 Spring JPA 调用存储过程的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Data Jpa 在 Oracle 中调用存储过程时参数的数量或类型错误

Spring data jpa 调用存储过程处理返回参数及结果集

尝试使用 Spring Data JPA 运行存储过程时出现“类型不能为空”异常

使用 jparepository 调用存储过程 Spring Boot 应用程序

spring-data-jpa 1.11.16 带游标的存储过程

基于Spring Boot,使用JPA动态调用Sql查询数据