【问题标题】:Spring Boot Data JPA receive Multiple Out Parameters from stored procedureSpring Boot Data JPA 从存储过程接收多个输出参数
【发布时间】:2020-08-22 14:41:14
【问题描述】:

我正在尝试通过 Spring Boot Data JPA (v2.2.6) 调用具有多个输出参数的存储过程,但收到错误:

DEBUG [http-nio-8080-exec-1] org.hibernate.engine.jdbc.spi.SqlStatementLogger: {call TEST_SP(?,?,?)}
RACE [http-nio-8080-exec-1] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [DOC_NAME] as [VARCHAR] - [ololo]
ERROR [http-nio-8080-exec-1] org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: OUT/INOUT parameter not available: DOC_ID; nested exception is java.lang.IllegalArgumentException: OUT/INOUT parameter not available: DOC_ID] with root cause
java.lang.IllegalArgumentException: OUT/INOUT parameter not available: DOC_ID

MS SQL Server 2012 中的存储过程:

CREATE PROCEDURE [dbo].[TEST_SP]
    @DOC_ID bigint output,
    @DOC_GUID nvarchar(255) output,
    @DOC_NAME nvarchar(255)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT @DOC_ID = 6666, @DOC_GUID = @DOC_NAME
END

这里是我的实体(与SP无关):

@Data
@Entity
@NamedStoredProcedureQuery(name = "SomeEntity.test", procedureName = "TEST_SP", parameters = {
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "DOC_ID", type = Long.class),
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "DOC_GUID", type = String.class),
        @StoredProcedureParameter(mode = ParameterMode.IN, name = "DOC_NAME", type = String.class)
})
@Table(name = "DOCUMENT_DATA")
public class SomeEntity {
    // some variables
}

这是我的存储库:

public interface SomeRepository extends JpaRepository<SomeEntity, Long> {

    @Procedure(name = "SomeEntity.test")
    Map<String, Object> testSp(@Param("DOC_NAME") String docName);
}

我是这样称呼它的:

@RestController
public class Controller {

    @Autowired
    SomeRepository repository;

    @GetMapping("test")
    String test() {
        return repository.testSp("ololo").toString();
    }
}

例如,我使用了这些链接: https://github.com/spring-projects/spring-data-jpa/blob/master/src/test/java/org/springframework/data/jpa/domain/sample/User.java#L77 https://github.com/spring-projects/spring-data-jpa/blob/e27933455efa6d1821dea23abd2bbe109b5d59a7/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java#L362

更新:我已尝试使用 Oracle 11g

CREATE OR REPLACE PROCEDURE test_sp(x OUT INTEGER, y OUT INTEGER) AS
BEGIN
  x := 17; y := 93;
END;


@NamedStoredProcedureQuery(name = "EstatementsDataEntity.test", procedureName = "test_sp", parameters = {
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "x", type = Integer.class),
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "y", type = Integer.class)
})

但收到几乎相同的错误:

java.lang.IllegalArgumentException: OUT/INOUT parameter not available: 1

【问题讨论】:

    标签: java spring-boot jpa stored-procedures spring-data-jpa


    【解决方案1】:

    我找不到带注释的有效解决方案并提交了错误DATAJPA-1722

    但我可以使用EntityManager 解决问题:

    @SpringBootTest
    class DemoApplicationTests {
    
        @PersistenceContext
        private EntityManager em;
    
        @Test
        void callStoredProcedureUsingEntitiManager() {
            StoredProcedureQuery proc = em.createStoredProcedureQuery("test_sp");
            proc.registerStoredProcedureParameter("x", Integer.class, ParameterMode.OUT);
            proc.registerStoredProcedureParameter("y", Integer.class, ParameterMode.OUT);
            proc.execute();
            assertThat(proc.getOutputParameterValue("x")).isEqualTo(17);
            assertThat(proc.getOutputParameterValue("y")).isEqualTo(93);
        }
    
    }
    

    【讨论】:

    • 带有@Procedure 注解的解决方案有什么更新吗?
    【解决方案2】:

    仅供仍在使用旧版本 Spring Boot 的任何人参考。此错误是由调用过程而不将其包含在事务中引起的。错误消息有点红鲱鱼,但解决方法是将@Transaction 添加到调用者。

    在上面的示例中,我将在 Controller 和 SomeRepository 之间包含一个服务层类,并将我的服务层方法注释为事务性。

    @Service
    public class SomeService{
        
        @Autowired
        SomeRepository someRepo;
    
        @Transactional
        public Map<String, Object> testSp(String docName){
            return someRepo.testSp(docName);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-06
      • 2015-12-26
      • 2018-08-06
      • 2016-07-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2020-09-21
      • 2019-01-23
      相关资源
      最近更新 更多