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)保证事务较短的执行时间,完成后马上提交。
这里有更加详细的描述:mysql官方解释

例子:
先建立以下一个表,并导入一些数据
CREATE TABLE `test_lock` (
    `id` INT ( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT,
    `uid` INT ( 11 ) NOT NULL DEFAULT '0' COMMENT '用户ID',
    `user_info` VARCHAR ( 45 ) NOT NULL DEFAULT '' COMMENT '用户信息',
    PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '死锁测试';
INSERT INTO `test_lock` ( `uid`, `user_info` ) VALUES ( '1', 'A' );
INSERT INTO `test_lock` ( `uid`, `user_info` ) VALUES ( '1', 'B' );
INSERT INTO `test_lock` ( `uid`, `user_info` ) VALUES ( '2', 'C' );
INSERT INTO `test_lock` ( `uid`, `user_info` ) VALUES ( '2', 'D' );

 

clientA执行:
注意,clientA不要COMMIT
START TRANSACTION;
UPDATE test_lock SET user_info = 'hello' WHERE `uid`=1 LIMIT 1;


 

 

clientB执行:

START TRANSACTION;
UPDATE test_lock SET user_info = 'world' WHERE `uid`=2 LIMIT 1;
COMMIT;

 

 

此时,clientB更新不会成功,虽然按数据来看,他们更新的行是不同的,但是由于uid上没有索引,这个走不了行锁,在uid上添加索引后,clientB就可以执行了。
这里用到的策略就是:事务操作锁定的行数较少
ALTER TABLE `test_lock`
ADD INDEX `idx_uid` USING BTREE (`uid` ASC);

 

 

 

 

 

 

posted @ 2020-06-04 16:45  GreenForestQuan  阅读(465)  评论(0)    收藏  举报