最近遇到一个MYSQL update 语句出现 Deadlock found when trying to get lock
的问题,分析一下原因。
1. 什么情况下会出现死锁?
https://dev.mysql.com/doc/refman/5.6/en/innodb-deadlocks.html
出现死锁需要2个条件:
- 至少2个client(A,B)同时在执行事务
- clientA锁定了某一行,未提交事务,此时clientB也需要update/delete这一行,此时clientB就会进入等待状态,直到出现Deadlock 。
2. 如何减少死锁的发生?
很重要的两点,就可以避免这种情况
- 事务操作锁定的行数较少(更精确的索引条件)。
- 保证事务较短的执行时间,完成后马上提交。
3. 例子
先建立以下一个表,并导入一些数据
CREATE TABLE `test_dead_lock` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户ID',
`message` varchar(45) NOT NULL DEFAULT '' COMMENT '用户信息',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='死锁测试'
INSERT INTO `vip_dap`.`test_dead_lock` (`uid`, `message`) VALUES ('1', 'aaa');
INSERT INTO `vip_dap`.`test_dead_lock` (`uid`, `message`) VALUES ('1', 'bbb');
INSERT INTO `vip_dap`.`test_dead_lock` (`uid`, `message`) VALUES ('2', 'ccc');
INSERT INTO `vip_dap`.`test_dead_lock` (`uid`, `message`) VALUES ('2', 'ddd');
clientA执行:
注意,clientA 不要COMMIT
START TRANSACTION;
UPDATE test_dead_lock SET message = 'u1' WHERE `uid`=1 LIMIT 1;
clientB执行:
START TRANSACTION;
UPDATE test_dead_lock SET message = 'u2' WHERE `uid`=2 LIMIT 1;
COMMIT;
此时,clientB 更新不会成功,虽然按数据来看,他们更新的行是不同的,但是由于uid上没有索引,这个走不了行锁。
在uid上添加索引后,clientB就可以执行了。
这里用到的策略就是:事务操作锁定的行数较少
ALTER TABLE `vip_dap`.`test_dead_lock`
ADD INDEX `idx_uid` USING BTREE (`uid` ASC);
版权声明:本文为CSDN博主「loophome」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/loophome/article/details/79867174