当前使用版本(必填,否则不予处理)

3.2.0

该问题是如何引起的?(确定最新版也有问题再提!!!)

MySQL InnoDB 在 RR 条件下,并发执行 IService 的 saveOrUpdate(行不存在),出现死锁

重现步骤(如果有就写完整)

写入不存在的行时,多个线程并发执行 saveOrUpdate

报错信息

线程一 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 817 page no 7434 n bits 88 index uniq_key of table table trx id 1 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 线程二 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 817 page no 7434 n bits 88 index uniq_key of table table trx id 2 lock_mode X locks gap before rec Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 817 page no 7434 n bits 88 index uniq_key of table table trx id 2 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0

*** WE ROLL BACK TRANSACTION (1)

问题出在 saveOrUpdate 的实现方式上,当前实现是先试图做 update,未成功后转而做 insert: 1. update 操作不存在的主键时,会加 gap key (S) 2. insert 操作时,会加 insert intention lock (X),此时有其他的 gap key 存在会等待 3. 第二个事务重复上面的步骤交替执行,产生死锁

Comment From: wlx381144235

我也碰到了这个问题 用的是3.4.0 老哥解决了吗?

Comment From: lzb6666

saveOrUpdate不是直接判断主键么,主键存在update,不存在save

Comment From: ByteGen

我也碰到了这个问题 用的是3.4.0 老哥解决了吗?

暂且通过其他方式绕过了: 1. 不使用原有的 saveOrUpdate 方法,自实现 insert ignore 方法替换 save 方法(MySQL) 2. 降低事务级别,非 RR 下不会加 gap key,不过会产生写入主键冲突

看具体的业务选择方式吧 @wlx381144235

Comment From: huayanYu

是重写了啥么? 默认的是先判断主键是否有值哇。 @ByteGen 有详细信息可以重新提交一个ISSUE给大家分析看看。

Comment From: JTongChen

是重写了啥么? 默认的是先判断主键是否有值哇。 @ByteGen 有详细信息可以重新提交一个ISSUE给大家分析看看。 MyBatis-Plus saveOrUpdate 并发下出现 deadlock 若通过wrapper条件调用saveOrUpdate,并且project_id + user_id是唯一索引,这种情况应该就会出现了