Hibernate事务疑惑:调用save后开启事务仍能持久化实体
关于Hibernate事务与save方法的解惑
首先拆解你遇到的核心问题:Hibernate的save()方法和事务的关系,以及数据真正持久化的时机。
1. save()方法的真实作用
session.save(firstUser)不会立刻把数据写入数据库,它只做两件事:
- 将实体对象纳入当前Session的「持久化上下文」,Hibernate会开始跟踪这个对象的所有状态变化;
- 为实体分配主键(如果使用自动生成主键策略,比如
@GeneratedValue)。
此时数据仅存在于内存中,完全没有同步到数据库。
2. 事务提交才是数据落地的关键
Hibernate通过事务界定数据库操作的原子性边界,只有当事务提交时,Hibernate才会执行「flush(刷新)」操作:把持久化上下文中所有未同步的变更(包括你save的对象)批量写入数据库。
如果不提交事务,这些内存中的变更永远不会被同步到数据库,一旦Session关闭或事务回滚,这些变更就会丢失——这正好对应你说的「不提交事务,实体就不会被持久化」的现象。
3. 为什么“先save再开事务”也能持久化?
你提到的「调用save后才开启事务仍能持久化」,本质原因是:
- 只要Session没有关闭,你在事务外
save的对象会一直留在持久化上下文中; - 当你后续开启事务并提交时,Hibernate会一次性把持久化上下文中所有变更(包括事务前
save的对象)flush到数据库。
注意:这种写法虽然能生效,但强烈不推荐在事务外执行save/update等变更操作——没有事务约束的话,一旦中间出现异常,你无法通过回滚撤销内存中的变更,极易导致数据不一致。
4. 你的代码细节纠正
看你贴的代码:
Session session = sessionFactory.openSession(); transaction = session.beginTransaction(); // 这里已经开启了第一个事务 firstUser = createUser("aaa@aa.com", "a", "yyy", true); session.save(firstUser); // 此时save是在事务范围内执行的 session.beginTransaction().commit(); // 这里实际提交的是之前开启的事务
你实际是先开启事务,再执行的save,本身就在事务范围内,提交后自然会持久化。如果是你描述的「先save再开事务」,就是上面第3点的机制在起作用。
标准的事务使用姿势
推荐的Hibernate事务操作流程应该是:
Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); // 所有数据库操作(save/update/delete/查询)都放在事务内 User user = createUser("aaa@aa.com", "a", "yyy", true); session.save(user); tx.commit(); // 提交事务,触发flush操作 } catch (Exception e) { if (tx != null) tx.rollback(); // 异常时回滚事务 throw e; } finally { session.close(); // 关闭Session释放资源 }
内容的提问来源于stack exchange,提问作者Sakib Shahriar
相关产品推荐
相关产品推荐

