MyBatis Plus:IService接口的saveBatch方法使用不当导致死锁。
补充:2021-01-14
之前的描述不严谨,Spring 事务还有个属性是 传播行为,默认是 PROPAGATION_REQUIRED,如果当前没有事务,则新建一个事务。
也就是本篇描述的问题还待深入研究,查问题确实存在。
问题
看起来的一个简单的更新方法,但导致了死锁,查看数据库事务日志,也没有其它SQL开启事务,但存在等待锁的事务。
业务
一个更新的业务,有一张主表,两个关联表。在一个更新的方法中,先修改主表,删除两个关联表数据,然后再插入新的数据到两个关联表。
- 在更新的方法上开启了事务。
- 插入新数据调了 Mybatis-Plus IService 接口的 saveBatch 方法来执行批量插入。
原因
根本原因就是更新方法开启了事务占用锁,内部调了 IService 接口的 saveBatch 方法来执行批量插入。
- 外层更新方法开启事务持有锁。
- 内部调了 saveBatch 来执行批量插入,而 Mybatis-Plus 的 IService 接口的 saveBatch 方法也是会开启事务的,就需要持有锁,但锁被外层事务占用,就会一直等待锁。
- 外层方法事务需要正常结束才会释放锁,而内部 saveBatch 会一直等待就不能正常结束。
- 这样就出现了死锁:即 A 等 B 正常结束才释放锁,而 B 必须先拿到锁才能正常结束。
- 直到 saveBatch 事务等待锁超时抛出异常才终止。
解决
在 XML Mapper 文件,使用 foreach 手写批量插入的SQL。不使用 Mybatis-Plus IService 接口的 saveBatch 方法。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载