1. 概述
在日常开发中,如果你在执行数据库修改操作时遇到了 TransactionRequiredException
异常,别慌,这其实是一个非常典型的错误。本文将带你分析这个异常出现的原因,并提供几种常见的解决方式。
2. TransactionRequiredException 是什么
✅ 这个异常通常出现在你尝试执行一个需要事务支持的数据库操作(如更新或删除)时,却没有开启事务。
来看个典型例子:
Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
执行这段代码时,你会看到类似下面的异常信息:
...
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
...
简单来说:你想动数据库,但没跟 Spring 或 Hibernate 打声招呼说你要开事务。
3. 解决方式:显式使用事务
最直接的办法就是手动把修改操作包裹在一个事务中:
Transaction txn = session.beginTransaction();
Query updateQuery
= session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
txn.commit();
上面这段代码中我们手动开启了事务并提交了它。
⚠️ 当然,在 Spring Boot 环境下,更推荐的做法是使用 @Transactional
注解来自动管理事务。
4. Spring 中的事务控制
如果你想要更精细地控制事务边界,可以考虑使用 Spring 提供的 TransactionTemplate
。
比如你有一个业务场景:先更新一篇文章,然后发送邮件通知。如果直接用 @Transactional
包裹整个方法:
public void update() {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
sendEmail();
}
可能会踩坑:即使更新失败抛出了异常,邮件也可能已经发出去了。 因为 @Transactional
默认是在方法结束时才提交事务。
为了避免这个问题,可以用 TransactionTemplate
显式控制事务提交时机:
public void update() {
transactionTemplate.execute(transactionStatus -> {
entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
// parameters
.executeUpdate();
transactionStatus.flush(); // 立即刷新并提交
return null;
});
sendEmail(); // 事务提交后再执行
}
这样就能确保数据库操作成功后再发邮件,避免副作用提前发生。
5. 总结
踩坑点 | 建议 |
---|---|
忘记加事务就执行 update/delete 操作 | ❌ 直接报错 |
使用 @Transactional 控制粒度不够 |
⚠️ 可能导致副作用提前执行 |
手动控制事务太麻烦 | ✅ 用 TransactionTemplate 更灵活 |
总的来说,任何涉及写操作的数据库访问都应该明确地包裹在事务中,这不仅是规范,更是防止数据不一致和脏写的最佳实践。
📌 本文适用于有一定经验的 Java 开发者,如果你对 JPA、Hibernate 和 Spring 的事务机制还不熟悉,建议先补补课再来看这篇文章。