MYSQL遇到Deadlock found when trying to get lock,解决方案

最近遇到一个MYSQL update语句出现Deadlock found when trying to get lock的问题,分析一下原因。

什么情况下会出现Deadlock found when trying to get lock?
出现死锁需要2个条件:
1)至少2个client(A,B)同时在执行事务
2)clientA锁定了某一行,未提交事务,此时clientB也需要update/delete这一行,此时clientB就会进入等待状态,直到出现Deadlock 。

如何减少死锁的发生?
很重要的两点,就可以避免这种情况
1)事务操作锁定的行数较少(更精确的索引条件)。
2)保证事务较短的执行时间,完成后马上提交。
这里有更加详细的描述:

例子:
先建立以下一个表,并导入一些数据
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);

猜你喜欢

转载自blog.csdn.net/loophome/article/details/79867174