innodb死锁1213 - Deadlock found when trying to get lock; try restarting transaction

问题背景:外网mysql在执行玩家保存数据的存储过程时,出现死锁 Deadlock found when trying to get lock; try restarting transaction

产生原因:两个线程AB提交事务时,对同一张表 test_deadlock(表名为化名)进行了如下操作:

  A线程根据表主键进行插入更新(insert into ON DUPLICATE KEY UPDATE ),此时为行锁,

  B线程对表进行删除部分数据(并不是根据主键),此时为表锁,

  A线程对表进行删除部分数据(并不是根据主键),此时为表锁。此刻,B线程错误提示死锁。

重现过程

CREATE TABLE `test_deadlock` (
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  `c` int(11) NOT NULL,
  PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `test_deadlock`(a,b,c) values(4,4,4) ON DUPLICATE KEY UPDATE b=4,c=4;
insert into `test_deadlock`(a,b,c) values(3,3,3) ON DUPLICATE KEY UPDATE b=3,c=3;
insert into `test_deadlock`(a,b,c) values(2,2,2) ON DUPLICATE KEY UPDATE b=2,c=2;
insert into `test_deadlock`(a,b,c) values(1,1,1) ON DUPLICATE KEY UPDATE b=1,c=1;

用Navicate 工具,打开AB两个窗口,

A窗口执行:

  start TRANSACTION;

  insert into `test_deadlock`(a,b,c) values(1,1,1) ON DUPLICATE KEY UPDATE b=1,c=1;

B窗口执行:

  update test_deadlock set b = 2 where b = 2;

A窗口执行:

  update test_deadlock set b = 4 where b = 4; 此刻B窗口提示死锁。

以上想重复实验,请在A窗口执行:commit;

如何避免死锁

  1.使用事务,但是避免使用长事务,将大事务拆小,分段多提交。

  2.sql语句条件是主键或者索引,这样执行后为行锁,避免表锁,从而避免死锁。

posted @ 2020-05-05 14:36  菜鸡徐思  阅读(3621)  评论(3编辑  收藏  举报