并发replace操作导致的死锁问题

2020-01-15 15:07:28 浏览数 (1)

//

并发replace操作导致的死锁问题

//

今天上班的时候,遇到了一个问题,有业务同学反应使用并发replace操作的时候,遇到了死锁的问题。针对这个问题,我看了看表的结构,发现表中有一个主键,一个唯一索引,然后用replace的操作去对表中的记录进行插入,如果存在相同的唯一索引,那么就更新这条记录。

开始分析这个问题之前,我们首先对replace into这个语法做个简单了解,replace into的语法是当我们不确定即将插入的记录是否存在唯一性冲突时,可以通过Replace into的方式让MySQL自动处理:当存在冲突时,会把旧记录替换成新的记录。

假设我们有表test

create table test (

a int auto_increment primary key,

b int,

c int,

unique key (b)

);

那么一个replace into的语句执行过程可能如下:

上面的图中,有几点需要解释:

1、当我们判断唯一索引的记录是否唯一时,需要对该条记录加上X锁,也就是第2步下面的判断时,需要加X锁

2、第5步检测该唯一索引,并对索引上的记录加X锁,在这个过程中,对于唯一索引对应的聚集索引记录,也需要加X锁。

3、第5步后面的条件判断的内容如下:

  • 如果发生uk冲突的索引是最后一个唯一索引、没有外键引用、且不存在delete trigger时,使用UPDATE ROW的方式来解决冲突;
  • 否则,使用DELETE ROW INSERT ROW的方式解决冲突。

详见:淘宝数据库月报

4、第6步和第7步,本质上是在更新唯一索引列上的记录。

5、第8步需要更新聚集索引列上的记录,该过程中,如果插入位置的下一条记录上存在记录锁,那么在插入时,当前session需要对其加插入意向锁,具体类型为LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION。这也是导致死锁的关键点之一

死锁成因分析:

1、假设我们有两个会话,也就是session

2、session1执行到第6或者第7步,准备更新唯一索引和聚集索引记录,更新前,需要持有该唯一索引和聚集索引的记录锁,假设该记录是unique key=2020的一条记录

3、此时session2发现了唯一索引冲突,也就是图中第2步下面的"判断重复记录"过程中,出现了索引冲突,也在记录上加X锁,假设该记录是unique key=2021的一条记录

4、session 1 在标记删除记录后,尝试插入新的unique key记录,发现预插入记录2020的下一条记录2021上有锁请求,因此尝试加插入意向X锁,导致死锁产生。

如何解决?

鉴于该业务表只有一个主键字段和一个唯一索引字段,在该情况下,我们可以使用insert into ... on duplicate key update的方法去代替replace的方法。

时间原因,今天的内容就到这里吧,不然超时了。。。

有帮助的话还希望点下再看哈

0 人点赞