当前使用版本(必填,否则不予处理)
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给大家分析看看。
若通过wrapper条件调用saveOrUpdate,并且project_id + user_id是唯一索引,这种情况应该就会出现了