
Hibernate 的事务必须在持久化操作(如 save)之前显式开启,否则会抛出异常;session.beginTransaction() 多次调用仅返回当前事务对象,不会创建新事务,因此 persist 操作实际发生在已开启的事务上下文中。
hibernate 的事务必须在持久化操作(如 save)之前显式开启,否则会抛出异常;`session.begintransaction()` 多次调用仅返回当前事务对象,不会创建新事务,因此 persist 操作实际发生在已开启的事务上下文中。
在 Hibernate(及 JPA)中,事务是持久化操作的必要执行环境,而非可选包装器。你提供的代码看似“先 save 后 beginTransaction”,实则存在关键误解:
Session session = sessionFactory.openSession();
transaction = session.beginTransaction(); // ✅ 此处已开启事务(transaction 对象被创建并绑定到 session)
firstUser = createUser("user@example.com", "a", "yyy", true);
session.save(firstUser); // ✅ 在已开启的事务中执行,状态进入一级缓存(pending insert)
session.beginTransaction().commit(); // ⚠️ 再次调用 beginTransaction() 仅返回同一 transaction 实例,随后 commit() 提交整个事务
关键点解析:
session.beginTransaction()是事务启动入口:首次调用时,Hibernate 创建Transaction实例,并将 session 置于事务上下文中;后续调用该方法不会开启新事务,而是直接返回当前已存在的事务对象(符合 Javadoc 规范:“Returns the current transaction, or starts a new one if none is associated with this session.”)。session.save()不立即执行 SQL,而是在事务提交(commit())或 flush 时才同步到数据库。若未开启事务就调用save(),Hibernate 会抛出TransactionRequiredException(JPA 标准行为),绝不会静默成功。-
你的代码中
save()实际发生在beginTransaction()之后,因此完全合法且符合预期。真正危险的是如下写法:Session session = sessionFactory.openSession(); session.save(entity); // ❌ 抛出 TransactionRequiredException session.beginTransaction().commit();
✅ 正确实践模式(推荐使用 try-with-resources + 显式异常处理):
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction(); // 必须在任何 DML 操作前调用
User user = createUser("user@example.com", "a", "yyy", true);
session.save(user); // 状态暂存于 Persistence Context
tx.commit(); // flush + commit → SQL INSERT 执行并提交
} catch (Exception e) {
if (tx != null) tx.rollback(); // 防止脏数据
throw e;
} finally {
session.close();
}
⚠️ 注意事项:
- 不要重复调用
beginTransaction()——它不是幂等的“启动开关”,而是“获取当前事务”的安全门。 - 使用
@Transactional(Spring)或 Jakarta EE 容器管理事务时,框架自动保障事务边界,避免手动误操作。 - 始终配对
commit()/rollback(),避免连接泄漏或事务悬挂。
总之:Hibernate 的事务模型严格遵循 ACID,所有持久化操作必须处于活跃事务内;所谓“先 persist 后事务”在语义上不成立——要么事务已开启,要么操作根本无法执行。










