Spring Boot3/Hibernate6下@Transactional无法启动事务问题排查
Spring Boot 3/Hibernate 6 事务注解失效排查与解决
问题情况
迁移到Spring Boot 3 + Hibernate 6环境后,Hibernate能正常解析实体、仓库,数据库连接也没问题,但@Transactional注解就是启动不了事务。
测试代码
@Component public class Test { @Autowired private EntityManagerFactory entityManager; @Transactional public void test() { Session s = entityManager.unwrap(SessionFactory.class).getCurrentSession(); s.createQuery("FROM sometable").list(); } }
报错信息
Caused by: org.hibernate.HibernateException: Calling method 'createQuery' is not valid without an active transaction (Current status: NOT_ACTIVE) at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:341)
当前配置
事务配置类
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages="com.somepackage") @EntityScan(basePackages="com.somepackage") public class TransactionConfig { ... }
application.properties中的会话配置
... spring.jpa.properties.hibernate.current_session_context_class=thread ...
删掉这个会话配置后,又报新错:
Caused by: org.hibernate.HibernateException: No CurrentSessionContext configured
补充测试结果
- 改用
@PersistenceUnit注入EntityManagerFactory,还是一样的无活跃事务错误。 - 直接调用继承
JpaRepository的类能跑,但会新建事务,完全无视父级的@Transactional。
解决办法
1. 删掉自定义的会话上下文配置
Spring Boot整合Hibernate时,会自动把CurrentSessionContext设为SpringSessionContext,手动加thread配置会覆盖这个逻辑,导致Spring的事务管理没法把会话绑定到事务里,直接删掉spring.jpa.properties.hibernate.current_session_context_class=thread就行。
2. 换用EntityManager注入
别直接用EntityManagerFactory,改用@PersistenceContext注入EntityManager,Spring会自动把它关联到当前事务的会话:
@Component public class Test { @PersistenceContext private EntityManager entityManager; @Transactional public void test() { Session s = entityManager.unwrap(Session.class); s.createQuery("FROM sometable").list(); } }
3. 确保事务注解被Spring代理生效
- 保证
Test类被Spring扫描到(已经加了@Component,没问题)。 - 别在类内部直接调用
@Transactional方法,Spring代理只对外部调用生效。 - 如果用JDK动态代理,要确保类实现了接口;或者开启CGLIB代理(Spring Boot默认已经开了),可以在配置类里显式设置:
@EnableTransactionManagement(proxyTargetClass = true)
4. 调整JpaRepository的事务传播行为
直接调用JpaRepository方法时,它自带的事务注解会覆盖父级事务。要是想让它沿用父级事务,需要在自定义仓库接口里重新声明方法,并指定事务传播属性为SUPPORTS:
public interface SomeRepository extends JpaRepository<SomeEntity, Long> { @Transactional(propagation = Propagation.SUPPORTS) List<SomeEntity> findAll(); }
内容的提问来源于stack exchange,提问作者user1432882
相关产品推荐
相关产品推荐

