MyBatisPlus:IService接口的saveBatch方法使用不当导致死锁

MyBatis Plus:IService接口的saveBatch方法使用不当导致死锁

问题

看起来的一个简单的更新方法,但导致了死锁,查看数据库事务日志,也没有其它SQL开启事务,但存在等待锁的事务。

业务

一个更新的业务,有一张主表,两个关联表。在一个更新的方法中,先修改主表,删除两个关联表数据,然后再插入新的数据到两个关联表。

  1. 在更新的方法上开启了事务。
  2. 插入新数据调了 Mybatis-Plus IService 接口的 saveBatch 方法来执行批量插入。

原因

根本原因就是更新方法开启了事务占用锁,内部调了 IService 接口的 saveBatch 方法来执行批量插入。

  1. 外层更新方法开启事务持有锁。
  2. 内部调了 saveBatch 来执行批量插入,而 Mybatis-Plus 的 IService 接口的 saveBatch 方法也是会开启事务的,就需要持有锁,但锁被外层事务占用,就会一直等待锁。
  3. 外层方法事务需要正常结束才会释放锁,而内部 saveBatch 会一直等待就不能正常结束。
  4. 这样就出现了死锁:即 A 等 B 正常结束才释放锁,而 B 必须先拿到锁才能正常结束。
  5. 直到 saveBatch 事务等待锁超时抛出异常才终止。

解决

在 XML Mapper 文件,使用 foreach 手写批量插入的SQL。不使用 Mybatis-Plus IService 接口的 saveBatch 方法。

MyBatisPlus:IService接口的saveBatch方法使用不当导致死锁

http://blog.gxitsky.com/2021/01/12/Mybatis-Plus-01-saveBatch-deadlock/

作者

光星

发布于

2021-01-12

更新于

2023-06-06

许可协议

评论