Spring中被挂起的@Transactional方法是否会阻塞持有数据库资源?
问题1:outer方法是否会在inner提交前持有用户资源的锁
是的,这个结论完全成立。
在你给出的Spring声明式事务逻辑中,outerMethod配置的是REQUIRED传播级别,执行testDAO.updateUser(user)时,会在当前事务中拿到对应用户行的排他锁(以最常用的InnoDB存储引擎为例)。而数据库事务的排他锁只有在当前事务提交或回滚时才会释放。
当调用someBean.innerMethod()时,因为innerMethod配置了REQUIRES_NEW传播级别,Spring会先将outerMethod的现有事务挂起,开启一个全新的独立事务执行innerMethod的逻辑,直到innerMethod的新事务提交完成后,才会恢复outerMethod的原有事务继续执行。
也就是说outerMethod的事务提交时机,一定是在innerMethod执行完成之后,所以updateUser拿到的锁,会贯穿整个innerMethod的执行周期,直到outerMethod最终提交才会释放。
问题2:是否可以类比为两个数据库控制台顺序执行
这个类比完全准确,执行流程和你列的步骤完全一致:
-- 第一个控制台(对应outer的原有事务) 1. begin; 2. update user set ...; -- 拿到对应用户行的锁,暂不释放 -- 第二个控制台(对应inner的REQUIRES_NEW新事务) 3. begin; 4. -- 执行inner中的所有业务逻辑 5. commit; -- inner事务提交完成 -- 回到第一个控制台 6. commit; -- 此时才释放update拿到的用户行锁
额外注意事项
这种写法有非常高的性能风险:
- 如果
innerMethod执行逻辑耗时较长,会导致用户行锁被长时间持有,大量请求操作同一用户时会直接产生大量锁等待,数据库吞吐骤降 - 如果
innerMethod中也需要修改同一个用户的数据,会直接触发死锁:outer事务持有锁等待inner执行完成,inner的新事务等待outer释放锁,两个事务互相等待永远无法结束
内容的提问来源于stack exchange,提问作者Ekaterina
相关产品推荐
相关产品推荐

