1. @Transactional 与事务边界在 JPA 的协作
在 JPA 中,@Transactional 注解与事务边界是如何协作的?请说明事务边界、持久化上下文(Persistence Context)与数据库连接之间的关系?
- 事务边界与持久化上下文生命周期
- 事务提交与 flush 时机
- 连接获取与释放的时机
@Transactional 声明了服务方法的事务边界。当方法进入时 Spring 开启事务并从连接池获取一个数据库连接,同时绑定一个持久化上下文(EntityManager);方法结束时提交或回滚事务。在 Spring 管理的事务型持久化上下文(transaction-scoped,JPA 默认类型)中,flush 默认在提交点之前自动执行(AUTO flush mode),将持久化实体的变更同步到数据库。查询、插入、更新、删除都通过这一条连接完成,真正体现了"一个事务一条连接"的边界。若方法抛异常,事务回滚,持久化上下文也会被标记为 rollback-only,后续操作会抛异常。
事务边界决定了持久化上下文的作用范围,也决定了数据库连接被占用的时间。事务期间持有连接,事务结束即释放连接,因此事务不能跨越远程调用或长耗时的非数据库操作,否则会长期占用连接。理解这个边界才能正确划分事务,避免连接池耗尽和一致性问题。
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Account a = accountRepository.findById(fromId).orElseThrow();
Account b = accountRepository.findById(toId).orElseThrow();
a.debit(amount); // 变更进入持久化上下文
b.credit(amount);
// 方法返回时 Spring 提交事务,flush 将变更写入数据库
}