设为首页 收藏本站
查看: 682|回复: 0

[经验分享] mysql 2个sql更新不同记录但死锁

[复制链接]

尚未签到

发表于 2016-10-19 07:51:19 | 显示全部楼层 |阅读模式
问题起因:
两条写sql,操作的记录没有任何冲突,但发生死锁
 
预备知识:
InnoDB行锁是通过给索引上的索引项加锁来实现的
 
创建测试表
CREATE TABLE `t1` (
  `pk_id` INT(11) NOT NULL,
  `type` INT(11) NOT NULL,
  `status` INT(11) NOT NULL,
  PRIMARY KEY (`pk_id`)
);
create index idx_type on t1(type);
create index idx_status on t1(status);
生成测试数据
INSERT INTO  t1 (pk_id,TYPE,STATUS)
VALUES
(1,1,0),
(2,1,0),
(3,1,0),
(4,2,0),
(5,2,0),
(6,1,1),
(7,1,1),
(8,2,1);
 
例1.不一样的锁等待
连接A执行
SET autocommit=0;
BEGIN;
SELECT * FROM t1 force index(PRIMARY) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;
马上返回查到的结果有两条pk_id为1和3
 
连接B执行
SET autocommit=0;
BEGIN;
SELECT * FROM t1 WHERE pk_id=2 FOR UPDATE;
执行后连接B一直是等待状态,如果连接A commit,连接B马上就执行完成
说明:连接A虽然查出来的结果只有pk_id为1和3的两条记录,但把pk_id为2的PRIMARY索引记录也锁住了,所以连接B一直等待
 
换个索引试试
在连接A里
commit;
SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;
注意只换了force index使用的索引,其他都没变
在连接B里想写操作TYPE=1的记录(pk_id为1、2、3、6、7)都等待,因为连接A把idx_type中TYPE=1的记录都锁了
和之前例子对照可以发现,索引锁是按使用的索引来操作,并且可以确定的是锁的范围会超出查询结果范围,这点和一般以为的不一样,具体算法还有待研究。
 
2.死锁
连接A执行
COMMIT;
SET autocommit=0;
SELECT * FROM t1 WHERE pk_id<5 FOR UPDATE;
连接A先锁住了pk索引的部分记录
 
接着连接B执行
COMMIT;
SET autocommit=0;
SELECT * FROM t1 FORCE INDEX (idx_status) WHERE STATUS=0 FOR UPDATE;
连接B锁往了idx_status的部分记录,再要锁pk时被连接A block,所以只能等待
 
最后连接A执行
UPDATE t1 SET STATUS=6 WHERE pk_id<5;
这时连接B报dead lock found
简单来讲连接A先锁住pk,B先锁住idx_status再拿pk就拿不到,这时A再拿idx_status就死锁了
类似于一个人有X但要Y,一个人有Y但要X,互不相让,就死锁了。
 
3.想不到的死锁
把例1和例2的情况结合起来,就会出来本文最开始碰到的问题,想不到的死锁,即更新的记录完全不冲突,但就是死锁了
比如
SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 FOR UPDATE;

update t1 set status=1 where pk_id=6
虽然想操作的记录不同,但锁的记录有相同的,所以也可能会死锁
 
例4.index merge死锁
如果sql where里同时使用了type和status,因为type和status上都有单字段索引,所以explain会发现使用了index merge
有的sql使用的索引是先idx_type再idx_status,有的先idx_status再idx_type
这样如果锁的记录有冲突,就可能和例3一样死锁了
 
解决方案:
1.只有一个pk,不要其他索引。这样只有lock wait,不会死锁
2.有多个index,但写数据时使用的都是同样的index组合
3.有多个index,按不同的index组合写数据,但逻辑上保证锁的记录不冲突
 
时间所限,只整理了大概的逻辑,一些细节未深入。有兴趣的可以看看mysql的next-key locking

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-288121-1-1.html 上篇帖子: MySQL: Left Join, Right Join and Inner Join, Outer Join 下篇帖子: Mysql 存储引擎中InnoDB与MyISAM的主要区别
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表