問題背景:外網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語句條件是主鍵或者索引,這樣執行后為行鎖,避免表鎖,從而避免死鎖。