美文网首页
Replace into频发死锁原因

Replace into频发死锁原因

作者: 爱钓鱼的码农 | 来源:发表于2020-11-11 16:51 被阅读0次

    背景

    Replace into操作可以算是比较常用的操作类型之一,当我们不确定即将插入的记录是否存在唯一性冲突时,可以通过Replace into的方式让MySQL自动处理:当存在冲突时,会把旧记录替换成新的记录。

    create table t1 (a int auto_increment primary key, b int, c int, unique key (b));
    并发执行SQL:replace into t1(b,c) values (2,3)
    

    Step 1. 正常的插入逻辑

    首先插入聚集索引记录,在上例中a列为自增列,由于未显式指定自增值,每次Insert前都会生成一个不冲突的新值。
    随后插入二级索引b,由于其是唯一索引,在检查duplicate key时,为其加上类型为LOCK_X的记录锁。

    Step 2. 处理错误

    由于检测到duplicate key,因此第一步插入的聚集索引记录需要被回滚掉(row_undo_ins)。

    Step 3. 转换操作

    从InnoDB层失败返回到Server层后,收到duplicate key错误,首先检索唯一键冲突的索引,并对冲突的索引记录(及聚集索引记录)加锁。
    随后确认转换模式以解决冲突:
    -如果发生uk冲突的索引是最后一个唯一索引、没有外键引用、且不存在delete trigger时,使用UPDATE ROW的方式来解决冲突;
    -否则,使用DELETE ROW + INSERT ROW的方式解决冲突。

    Step 4. 更新记录

    对于聚集索引,由于PK列发生变化,采用delete + insert 聚集索引记录的方式更新。
    对于二级uk索引,同样采用标记删除 + 插入的方式。
    我们知道,在尝试插入一条记录时,如果插入位置的下一条记录上存在记录锁,那么在插入时,当前session需要对其加插入意向锁,具体类型为LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION。这也是导致死锁的关键点之一。

    tips:
    默认情况下,参数innodb_autoinc_lock_mode的值为1,因此只在分配自增列时互斥(如果我们将其设为0的话,就会产生AUTO_INC类型的表级锁)。当分配完自增列值后,我们并不知道并发的replace into的顺序。

    相关文章

      网友评论

          本文标题:Replace into频发死锁原因

          本文链接:https://www.haomeiwen.com/subject/gkolbktx.html