【mysql】一次奇怪的replace into死锁

【mysql】一次奇怪的replace into死锁

时间:2015-12-27 02:12:42      作者:beebol      标签: gap锁 next key replace into 死锁      分类: mysql

最近碰到一次死锁,开始看比较奇怪,两个replace into不同记录怎么造成了死锁,其实没有想的这么简单。具体看如下图:

replace

单纯的看show engine innodb status的死锁信息,还不是很明确,因为只能看到目前事务1正在等待uk_a_b_c索引上的lock_mode X.而事务2已经持有lock_mode X,正在等等IX锁(lock_mode X locks gap before rec insert intention waiting)。两个都是在不同的记录上等待,

事务1的语句是:replace into tt (a,b,c,d)values(89,123,1,'xx-343s3');

事务2的语句是:replace into tt (a,b,c,d)values(86,123,1,'xx-3s3');

看到这里时,感觉很奇怪,为什么这两个sql会造成死锁,后面分析了全日志才知道,还存在一条sql。它是:replace into tt (a,b,c,d)values(89,123,1,'xx-3s3'),看到这条sql后,感觉发现了问题。

首先确认两个tips:

1、replace into时,如果记录存在会加Next Key锁(x+gap)2、对记录操作时,必须持有页锁(比如说修改记录得先申请页锁,然后再申请X,再修改数据页,如果需要等待锁,会立即释放掉页锁;获得X锁后,得重新申请页面锁)

2、对记录操作时,必须持有页锁(比如说修改记录得先申请页锁,然后再申请X,再修改数据页,如果需要等待锁,会立即释放掉页锁;获得X锁后,得重新申请页面锁)

实验环境:mysql 5.1.63  + redhat6u5

表结构:

CREATE TABLE `tt` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `a` int(8) NOT NULL,
  `b` int(8) NOT NULL,
  `c` int(8) NOT NULL,
  `d` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_a_b_c` (`a`,`b`,`c`)) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8
) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8

插入的数据:

mysql> select * from tt;          
+----+----+-----+---+----------+
| id | a  | b   | c | d        |
+----+----+-----+---+----------+
|  1 | 85 | 234 | 2 | zz       |
| 71 | 86 | 123 | 1 | yy-2xssd |
| 73 | 89 | 123 | 1 | yy-2sss  |+----+----+-----+---+----------+
+----+----+-----+---+----------+

如下是具体的执行步骤:

 session1  session2  session3
 start transaction; replace into tt (a,b,c,d)values(89,123,1,'xx-3s3'); 记录存在,标记删除后,再insert新记录,持Next key锁
 start transaction; replace into tt (a,b,c,d)values(86,123,1,'xx-3s3'); 请求Next key锁,被session1中的Next key锁住,等待(lock_mode X waiting)
 start transaction; replace into tt (a,b,c,d)values(89,123,1,'xx-343s3'); 获得页面锁,被session1锁定,释放页面锁,等待Next key锁;(lock_mode X waiting)
 commit;
 session1提交后,成功获取Next key锁
 session1提交后,发现记录已经被修改,restart,重新判断记录状态,成功获得页面锁,发现数据记录存在,准备获取Next key锁,由于session3已经有next key锁,等待(lock_mode X waiting)
 标记数据为删除状态,准备插入记录,请求IX锁,但被与session2请求的Next Key锁冲突( lock_mode X locks gap before rec insert intention waiting)
 ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 这里防止session2饿死,根据权重将session2回滚

 

时间:2015-12-27 02:12:42      作者:beebol      标签: gap锁 next key replace into 死锁      分类: mysql
  • 分享到:
  • 微博
  • QQ空间
  • 腾讯微博
  • 微信

Copyright © 2015 Gitblog | Proudly powered by Gitblog.