从Hibernate3.x升级到5.x后执行原生更新查询遇事务异常求助
解决Hibernate 5.x + Spring 5.x中执行原生更新/删除SQL时的TransactionRequiredException问题
我刚帮几个从Hibernate/Spring 3.x升级到5.x的开发者搞定过一模一样的问题——你遇到的TransactionRequiredException本质是Hibernate 5对DML操作的事务校验变得更严格,再加上Spring 5的事务管理逻辑有细节调整,光加@Transactional有时候确实踩不到点上。结合你提到的旧方法场景,我给你梳理几个必查的解决方向:
1. 先确认@Transactional真的生效了
很多时候不是注解没用,是你用错了场景:
- 注解必须加在public方法上:Spring AOP默认只代理public方法,非public方法的
@Transactional会直接被忽略。如果你的更新方法是private/protected,赶紧改成public。 - 别在同一个类内部调用事务方法:比如你在类A的
methodA()里调用了本类加了@Transactional的updateData(),这种内部调用Spring拦截不到,事务根本不会开启。解决办法要么把事务方法抽到单独的Bean里,要么用AopContext.currentProxy()来调用(记得开启exposeProxy = true)。 - 检查事务传播属性:如果你的方法被另一个事务方法调用,传播属性是不是被设成了
NOT_SUPPORTED/NEVER?这种会强制关闭事务。可以显式指定@Transactional(propagation = Propagation.REQUIRED)(默认就是这个,但有时候会被全局配置覆盖)。
2. 适配Hibernate 5的原生SQL执行姿势
Hibernate 3.x里,有时候没显式事务也能执行update/delete(Hibernate会偷偷开临时事务),但5.x直接堵死了这个漏洞,必须在活跃事务上下文里执行DML:
如果你用Hibernate原生Session:
确保Session是Spring管理的(比如通过@Autowired SessionFactory获取,别自己new Session),然后在事务方法内执行:
@Transactional public void updateUserStatus(Long userId) { String sql = "UPDATE user SET status = 1 WHERE id = :userId"; session.createSQLQuery(sql) .setParameter("userId", userId) .executeUpdate(); }
如果你用JPA EntityManager:
同样要确保EntityManager是Spring注入的,然后在事务内调用executeUpdate():
@Transactional public void updateOrderStatus(Long orderId) { String sql = "UPDATE orders SET status = 'completed' WHERE id = ?1"; entityManager.createNativeQuery(sql) .setParameter(1, orderId) .executeUpdate(); }
3. 排查配置层面的问题
- 确认事务管理器是适配Hibernate 5的:如果用原生Hibernate,用
HibernateTransactionManager;如果用JPA,用JpaTransactionManager但要确保EntityManagerFactory是Hibernate 5的实现(比如配置hibernate.version为5.x)。 - 检查
@EnableTransactionManagement(XML的话是<tx:annotation-driven/>)有没有配置对,扫描的包路径要包含你的业务类。
4. 验证事务是否真的活跃
可以在方法里加一行代码快速验证:
import org.springframework.transaction.support.TransactionSynchronizationManager; @Transactional public void yourUpdateMethod() { // 打印当前是否有活跃事务 boolean hasActiveTx = TransactionSynchronizationManager.isActualTransactionActive(); System.out.println("当前事务状态:" + hasActiveTx); // 执行你的原生SQL... }
如果打印false,说明事务确实没生效,回到前面的配置和调用场景排查;如果是true还报错,那可能是Hibernate Session和Spring事务没绑定,这时候要检查SessionFactory的配置是否正确。
按照这个流程排查,90%以上的情况都能解决问题——我之前遇到的案例里,最多的坑就是内部方法调用导致事务注解没生效,其次是用了自己手动创建的Session/EntityManager。
内容的提问来源于stack exchange,提问作者Shahe
相关产品推荐
相关产品推荐

