Spring Boot JPA调用PostgreSQL存储过程报错求助
已创建的存储过程
CREATE OR REPLACE PROCEDURE reset_disabled() LANGUAGE plpgsql AS $$ DECLARE BEGIN UPDATE regional_price_info SET disabled = NULL; END; $$;
两种调用方式及报错情况
1. 使用@Query注解调用
代码:
@Query(value = "CALL reset_disabled();", nativeQuery = true) void priceActivator();
报错信息:
org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
2. 使用@Procedure注解调用
代码:
@Procedure(value = "reset_disabled") void priceActivator2();
报错信息:
2023-02-22T07:43:00,013 [scheduling-1] [INFO ] com.zageno.pricing.activator.PriceActivator priceActivatorByValidity [28] - Triggering price activator procedure
Hibernate: {call reset_disabled()}
2023-02-22T07:43:00,016 [scheduling-1] [WARN ] org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions [137] - SQL Error: 0, SQLState: 42809
2023-02-22T07:43:00,017 [scheduling-1] [ERROR] org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions [142] - ERROR: reset_disabled() is a procedure
Hint: To call a procedure, use CALL.
Position: 15
这里Hibernate生成了{call reset_disabled()}的调用语句,但PostgreSQL报错要求用CALL,看似矛盾,实际是Hibernate的JDBC调用格式与PostgreSQL存储过程调用语法不兼容导致。
解决方法
方法1:修正@Query注解配置
存储过程执行的是UPDATE操作,无结果集返回,需添加@Modifying注解告知JPA无需提取结果集,同时确保调用处于事务环境中:
@Modifying @Transactional @Query(value = "CALL reset_disabled();", nativeQuery = true) void priceActivator();
方法2:调整@Procedure注解及方言配置
指定正确的存储过程名称,并添加事务支持,同时配置Hibernate适配PostgreSQL方言:
@Transactional @Procedure(procedureName = "reset_disabled") void priceActivator2();
在配置文件中添加:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.proc.param_null_passing=true
方法3:通过EntityManager直接调用
绕过Spring Data的封装,直接用EntityManager执行存储过程:
@Autowired EntityManager entityManager; @Transactional public void callResetDisabled() { entityManager.createNativeQuery("CALL reset_disabled()").executeUpdate(); }
原因解析
- 第一种@Query报错:JPA默认期望查询返回结果集,但该存储过程仅执行更新操作,无结果集,需
@Modifying注解标记为修改类操作。 - 第二种@Procedure报错:Hibernate生成的
{call ...}是JDBC标准调用格式,PostgreSQL对存储过程调用要求更严格,需直接使用CALL语句,配置正确方言或直接用EntityManager可解决该兼容性问题。
内容的提问来源于stack exchange,提问作者user1073214

