龙空技术网

MYSQL ON DUPLICATE KEY UPDATE 死锁问题

码农三石 190

前言:

目前我们对“mysqlforupdate死锁”大概比较重视,朋友们都需要了解一些“mysqlforupdate死锁”的相关知识。那么小编同时在网摘上收集了一些关于“mysqlforupdate死锁””的相关知识,希望看官们能喜欢,看官们一起来了解一下吧!

前言

工作中我们会经常遇到这样的场景,插入一条数据,当不存在时新增,存在时更新某些字段或者某些字段执行累计等操作。

首先想到的就是使用INSERT ... ON DUPLICATE KEY UPDATE语句,一条语句搞定查询是否存在和插入或者更新好几个步骤,但是该用法在MYSQL InnoDB 5.0以上版本有很多bug,有可能导致死锁也有可能导致主从模型下replication产生数据不一致。

死锁

INSERT ... ON DUPLICATE KEY执行时,InnoDB引擎会先判断插入的行是否产生DUPLICATE KEY ERROR,如果存在,在对该现有的行加上S(共享锁)锁,并返回该行数据给MYSQL,然后MYSQL执行完DUPLICATE后的UPDATE操作,然后对该记录加上X(排他锁),最后进行UPDATE写入。

如果有两个事务并发的执行同样的语句,那么就会产生death lock,如:

时间

事务T1

事务T2

time1

执行INSERT ON DUPLICATE KEY

time2

key存在,获取该行的S锁,获取行数据

执行INSERT ON DUPLICATE KEY

time3

修改获取的行数据

key存在,获取该行的S锁,获取行数据

time4

修改获取的行数据

time5

修改结果写入存储引擎,该行加X锁,T2存在S锁,等待T2释放S锁

time6

修改结果写入存储引擎,该行加X锁,T1存在S锁,等待T1释放S锁

time7

死锁

数据不一致

MySQL Bugs: #58637: Mark INSERT...ON DUPLICATE KEY UPDATE unsafe when there is more than one key

当MYSQL执行INSERT ON DUPLICATE KEY的INSERT时,存储引擎会检查插入的行是否会产生重复键错误。如果是的话,它会将现有的行返回给MYSQL,MYSQL会更新它并将其发送回存储引擎。

当表具有多个唯一或主键时,此语句对存储引擎检查密钥的顺序非常敏感。根据这个顺序,存储引擎可以确定不同的行数据给到MYSQL,因此MYSQL可以更新不同的行。

存储引擎检查key的顺序不是确定性的,当表存在主键和多个唯一键时,InnoDB优先按照主键来检查,其他按照索引添加到表的顺序检查。

由于存储引擎检查KEY的顺序不确定性,当Master和Slave的索引创建顺序不一致时,且基于SQL语句的复制(statement-based replication, SBR)时,主从复制的数据不一致,因为主从节点的存储引擎依据索引的创建顺序返回不同的行数据;基于行的复制(row-based replication, RBR)可以FIX该bug。

标签: #mysqlforupdate死锁