
Hibernate 的事务必须在执行持久化操作前显式开启,session.save() 等操作本身不触发立即数据库写入,而是将变更暂存于一级缓存;真正落库依赖于事务提交(commit),而非调用 save() 的时机。
hibernate 的事务必须在执行持久化操作前显式开启,`session.save()` 等操作本身不触发立即数据库写入,而是将变更暂存于一级缓存;真正落库依赖于事务提交(`commit`),而非调用 `save()` 的时机。
在 Hibernate(及 JPA)中,事务是数据一致性的核心保障机制。一个常见误区是认为调用 session.save() 或 em.persist() 就会立刻执行 SQL INSERT——实际上,这些方法仅将实体标记为“托管(managed)”并注册到当前 Session 的一级缓存中,真正的数据库写入延迟到事务提交时才批量执行(flush)。
你提供的代码存在两个关键问题:
Session session = sessionFactory.openSession();
transaction = session.beginTransaction(); // ✅ 正确:开启事务
firstUser = createUser("user@example.com", "a", "yyy", true);
session.save(firstUser); // ✅ 在事务内调用,合法且安全
session.beginTransaction().commit(); // ❌ 错误:重复调用 beginTransaction() 不开启新事务,但 commit() 仍作用于原事务
⚠️ 注意:session.beginTransaction() 是幂等操作——若当前 Session 已存在活跃事务,它不会创建新事务,而是直接返回该事务对象。因此 session.beginTransaction().commit() 实际提交的仍是首次开启的那个事务(即 transaction),并非“新开事务再提交”。
✅ 正确写法应明确管理事务生命周期:
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction(); // 启动事务
User firstUser = createUser("user@example.com", "a", "yyy", true);
session.save(firstUser); // 持久化操作在事务内完成
tx.commit(); // 提交:触发 flush + INSERT SQL 执行
} catch (Exception e) {
if (tx != null) tx.rollback(); // 异常时回滚
throw e;
} finally {
session.close();
}
? 关键要点总结:
-
事务必须先于
save()/persist()调用开启,否则抛出TransactionRequiredException(在 JPAEntityManager中)或导致未定义行为(原生 Hibernate Session 在无事务时可能允许 save,但变更永不提交); -
save()仅注册实体,不发送 SQL;SQL 执行由flush()触发,默认在commit()前自动调用; - 一个 Session 同一时刻只能有一个活跃事务,重复
beginTransaction()不会覆盖或嵌套事务(Hibernate 不支持物理嵌套事务); - 始终配对使用
beginTransaction()/commit()或rollback(),避免资源泄漏与数据不一致。
掌握这一流程,才能真正驾驭 Hibernate 的事务语义,写出可靠、可测试的数据访问逻辑。










