执行Update/Delete查询触发javax.persistence.TransactionRequiredException问题
我之前也踩过这个坑,结合你给出的异常栈信息,咱们来拆解下问题根源和对应的解决办法:
首先先把你遇到的异常栈贴出来方便参考:
javax.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1496) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final] at org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:256) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:590) ~[spring-data-commons-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578) ~[spring-data-commons-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) ~[spring-data-jpa-2.0.5.RELEASE.jar:2.0.5.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.5.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at com.sun.proxy.$Proxy93.existProjectTasks(Unknown Source) ~[na:na] at ca.projectmanagementapis.projectmanagementproject.daoImplementation.ProjectManagementAPIsReadMethodsDAO.getProjectTaskExist(ProjectManagementAPIsReadMethodsDAO.java:271) ~[classes/:na] at ca.projectmanagementapis.projectmanagementproject.daoImplementation.ProjectManagementAPIsReadMethodsDAO$$FastClassBySpringCGLIB$$c3d37619.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:747) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
异常原因分析
这个异常的核心是:当你执行更新/删除类型的JPQL查询时,当前线程没有绑定活跃的数据库事务。从你的调用链能看到,虽然Spring的TransactionInterceptor已经在调用链里,但事务并没有正确生效,常见的触发场景有这几种:
- Spring Data JPA的Repository接口中,执行更新/删除的方法缺少
@Modifying和@Transactional注解 - 事务注解的传播行为配置错误(比如用了
SUPPORTS/NOT_SUPPORTED,不会主动开启事务) - 调用Repository的上层方法(比如你的
ProjectManagementAPIsReadMethodsDAO.getProjectTaskExist)没有事务,且Repository的事务注解因为Spring AOP代理问题没生效 - 自定义DAO实现类中直接调用EntityManager执行更新,但没在事务上下文里
具体解决办法
针对上述场景,一一对应解决:
1. 给Repository的修改方法补全注解
如果是Spring Data JPA的Repository接口方法,必须同时添加@Modifying(告诉Spring这是修改类查询)和@Transactional(开启事务):
@Repository public interface TaskRepository extends JpaRepository<Task, Long> { // 示例:删除指定项目下的任务 @Modifying @Transactional @Query("DELETE FROM Task t WHERE t.projectId = :projectId") void deleteTasksByProjectId(@Param("projectId") Long projectId); }
注意:@Transactional可以加在Repository方法上,也可以加在调用它的Service层方法上(更推荐,因为事务通常在业务层管控)。
2. 检查事务传播行为
确保你的@Transactional注解的propagation属性是默认的REQUIRED(如果没有手动配置,默认就是这个),不要用SUPPORTS或者NOT_SUPPORTED——这俩不会主动开启新事务,只有当已有事务存在时才会加入。
3. 确保Spring AOP能代理到你的类
看你的异常栈,调用了自定义DAO类ProjectManagementAPIsReadMethodsDAO的方法,要确保:
- 这个类被Spring容器管理(加了
@Repository或者@Component注解) - 如果这个类的方法直接调用了需要事务的更新/删除操作,要么在该方法上加
@Transactional,要么在调用它的Service层方法上加@Transactional
比如你的getProjectTaskExist方法如果内部触发了更新/删除,就给它加注解:
@Repository public class ProjectManagementAPIsReadMethodsDAO { @Autowired private TaskRepository taskRepository; @Transactional // 加上这个注解,确保方法在事务内执行 public boolean getProjectTaskExist(Long projectId) { // 这里调用taskRepository的修改方法,或者自己用EntityManager执行更新 return taskRepository.existsByProjectId(projectId); } }
4. 手动使用EntityManager时要确保在事务内
如果是直接用EntityManager执行更新/删除,必须在事务方法内调用:
@Transactional public void updateTaskStatus(Long taskId, String newStatus) { entityManager.createQuery("UPDATE Task t SET t.status = :status WHERE t.id = :taskId") .setParameter("status", newStatus) .setParameter("taskId", taskId) .executeUpdate(); }
5. 确认Spring事务配置已开启
最后检查下你的Spring配置:
- 如果是Java配置类,要加
@EnableTransactionManagement注解 - 如果是XML配置,要添加
<tx:annotation-driven/>标签
这样Spring才能识别@Transactional注解并创建事务代理。
内容的提问来源于stack exchange,提问作者timisenco

