You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用jakarta.persistence.Query执行SQL函数时提交异常求助

问题根源

核心矛盾是Spring事务管理和PostgreSQL DO块内部的自主事务控制冲突:

  • 方法上加了@Transactional,Spring会自动开启一个外层事务
  • 但你的PL/pgSQL DO块里包含多个COMMIT/ROLLBACK语句,这些语句会直接操作数据库连接的事务状态,和Spring的外层事务逻辑完全冲突
解决方案

1. 移除方法上的@Transactional注解

你的DO块本身已经完成了事务的提交/回滚控制,不需要Spring再套一层事务。Spring的事务管理器会在方法结束时尝试提交已经被DO块提交过的连接,这就是"Unable to commit against JDBC Connection"报错的直接原因。

2. 恢复默认数据源配置

删掉以下两个配置,恢复默认值即可:

spring.datasource.hikari.auto-commit=false
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true

没有@Transactional时,JDBC连接会使用自动提交模式,DO块内部的事务控制可以正常执行。

3. 修正Java代码

DO块是无返回值的匿名代码块,不需要指定Long.class参数,直接执行即可:

public int executeRunFunctions() {
    Query query = entityManager.createNativeQuery(loadQuery("/script4.sql"));
    query.executeUpdate(); // DO块执行后返回0,因为没有影响行数
    return 0;
}
报错原因详解
  • 初始报错invalid transaction termination:Spring开启的外层事务还未结束,DO块里的COMMIT试图终止这个事务,PostgreSQL不允许在一个已有事务的上下文中显式执行自主事务控制语句。
  • 添加配置后的报错:虽然禁用了Hibernate的自动提交,但Spring事务管理器仍会在方法结束时尝试提交连接,而DO块已经提前完成了提交,连接处于已提交状态,再次提交就会报错,但DO块内的逻辑已经执行完毕,所以数据库中能看到执行结果。
额外注意

如果你的业务需要DO块和其他数据库操作在同一个事务中,那必须重构DO块,移除内部的COMMIT/ROLLBACK语句,把事务控制权交给Spring。但从你的DO块结构来看,它是一个包含多次提交的独立批量处理逻辑,这种场景下让它脱离Spring事务管理是更合理的选择。

内容的提问来源于stack exchange,提问作者Денис Кондратов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:38:17