一次离奇的 MySQL 死锁分析

2016 年 11 月 24 日2030

  

  1、故事起因于2016年11月15日的一个生产bug。业务场景是:归档一个表里边的数据到历史表里边,同是删除主表记录。

  2、背景场景简化如下(数据库引擎InnoDb,数据隔离级别RR[REPEATABLE])

  3、具体执行顺序

Transcation1 Transcation2 begin;

  — 这条sql得到test1表主键索引锁共享锁S(id=1) insert into test2 select * from test1 where id = 1;

begin;

  — 这条sql试图获取test1表主键索引锁共享锁S(id=1),但是已经被T1占有,所以它进入锁请求队列.

  insert into test2 select * from test1 where id = 1;

— 这条sql试图把自己拥有的test1表主键索引锁共享锁S(id=1)升级为排它锁X(id=1)

  — 这时T1也发起一个锁请求,这个时候mysql发现锁请求队列里边已存在一个事物T2对(id=1)的这条记录申请了S锁,死锁产生了。

  delete from test1 where id = 1;

死锁产生后mysql根据两个事务的权重,事务2的权重更小,被选为死锁的牺牲者,rollback。 T2 rollback 之后T1成功获取了锁执行成功

  Mysql 官方解释

  Deadlock occurs here because client A needs an X lock to delete the row. However, that lock request cannot be granted because client B already has a request for an X lock and is waiting for client A to release its S lock. Nor can the S lock held by A be upgraded to an X lock because of the prior request by B for an X lock. As a result, InnoDBgenerates an error for one of the clients and releases its locks. The client returns this error。

  实际场景和mysql文档有些区别,文档里边要获取的是X锁。具体事例里边要获取的是S锁。

  Mysql 官方文档:http://http://www.zjjv.com///doc/refman/5.7/en/innodb-deadlock-example.html

  

  目前100000+人已关注加入我们

  

  

  

  

  

  加社群小助手申请入群(请注明“php”),专业交流微信群期待你的加入~

  如果觉得我精彩的话,就分享到朋友圈让更多小伙伴看到吧~

微信搜索并关注科技讯公众账号:kejixun 更多精彩,早知道!

0 0