Spring中@Transactional事务什么时候提交?

Spring中@Transactional事务什么时候提交?
最新回答
﹌傲似。表情帝╯▽╰

2022-01-23 19:09:53

在Spring中,@Transactional注解的事务提交时间点是方法执行结束后。具体来说,Spring通过AOP(面向切面编程)框架实现事务管理,其核心流程如下:

  1. 事务开启:在目标方法执行前,Spring的代理逻辑会开启一个新事务(或加入现有事务)。
  2. 方法执行:目标方法内的数据库操作会被纳入当前事务上下文中。
  3. 事务提交当方法执行结束后,Spring的代理逻辑会检查是否抛出异常:

    若未抛出异常,则提交事务。

    若抛出未捕获的异常,则回滚事务。

关键细节说明
  • 提交时机:事务提交发生在方法返回之后(即finally块之前),而非方法执行过程中。这意味着方法内的所有操作(包括锁的释放)在事务提交前已完成。
  • 动态代理机制:Spring通过JDK动态代理或CGLIB生成代理类,在代理类的invoke方法中插入事务逻辑(如TransactionInterceptor)。
并发场景下的超卖问题

在并发环境中,若锁的释放(如lock.unlock())发生在事务提交之前,可能导致其他线程在事务未提交时读取到旧数据(如库存未减少),从而引发超卖。例如:

  1. 线程1执行方法,减少库存但未提交事务。
  2. 线程1释放锁。
  3. 线程2获取锁并读取库存,此时仍看到旧值,重复减少库存。
解决方案

为避免超卖,需确保事务提交在锁释放之前。可通过以下方式重构代码:

public Result func(long seckillId, long userId) { lock.lock(); // 先加锁 try { // 1. 查询库存(当前线程可见,因锁阻塞其他线程) // 2. 减少库存(操作纳入事务) // 3. 方法返回时,Spring代理提交事务(在lock.unlock()之前) return Result.SUCCESS; } finally { lock.unlock(); // 事务已提交,其他线程可见最新数据 }}

关键点

  • 锁的粒度:确保锁覆盖事务内的所有关键操作(如库存检查与修改)。
  • 隔离级别:默认的READ_COMMITTED或REPEATABLE_READ可避免脏读,但需结合锁机制防止并发修改。
其他注意事项
  • 异常处理:若方法抛出异常,事务会在抛出前回滚(仍遵循“方法结束后”逻辑)。
  • 性能影响:长时间持有锁会降低并发性能,需权衡一致性与吞吐量。

通过理解事务提交时机与并发控制的结合,可以有效避免超卖等竞态条件问题。