mysql insert 锁
擼了今年阿里、頭條和美團的面試,我有一個重要發現.......>>>
多線程插入mysql時會發生死鎖。
數據庫test中,id1和id2是聯合主鍵
當前數據庫test內容為空。mysql引擎是:InnoDB,隔離級別為REPEATABLE-READ
?
情況一:
線程A開啟事務:
mysql> start transaction; Query OK, 0 rows affected mysql>線程B開啟事務:
mysql> start transaction; Query OK, 0 rows affected mysql>線程A,插入數據:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql>線程A沒有commit,所以數據('1', '1'),('2', '2'),('3','3')被上鎖,
線程B這時也插入數據:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('2', '2'),('4','4'); 等待中....因為數據('2','2')被上鎖,所以等待線程A釋放鎖,此時數據('4','4')還沒有被上鎖。線程A可以插入('4','4');
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql> INSERT ignore into test values ('5', '5'),('4', '4') ; Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>線程A提交:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql> INSERT ignore into test values ('5', '5'),('4', '4') ; Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql> commit; Query OK, 0 rows affectedmysql>線程B提交:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('2', '2'),('4','4'); Query OK, 0 rows affected Records: 2 Duplicates: 2 Warnings: 2mysql> commit; Query OK, 0 rows affected情況二:
線程A開啟事務:
mysql> start transaction; Query OK, 0 rows affected mysql>線程B開啟事務:
mysql> start transaction; Query OK, 0 rows affected mysql>線程A,插入數據:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql>線程A沒有commit,所以數據('1', '1'),('2', '2'),('3','3')被上鎖,
線程B這時也插入數據:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('4', '4'),('2','2'),('5','5'); 等待中....因為數據('2','2')被上鎖,所以等待線程A釋放鎖,此時數據('4','4')已經成功執行被上鎖。線程A插入('4','4');會造成死鎖
A線程插入('4','4'),('5','5'):
mysql> INSERT ignore into test values ('4', '4'),('6', '6') ; Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>此時B線程檢測到死鎖:
mysql> INSERT ignore into test values ('4', '4'),('2','2'),('5','5'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>也就是說
A線程執行insert?ignore?into?test?values ('1', '1'),('2', '2');能執行成功,會給('1', '1'),('2', '2')加鎖
B線程執行insert?ignore?into?test?values ('3', '3'),('2', '2'),('4','4');檢測('3','3')沒有加鎖,然后給('3','3')加上鎖,('2','2')檢測到鎖,被A線程鎖住,等待鎖釋放,這時('4','4')這條數據沒有加鎖。
接下來:
?死鎖的方向
線程B死鎖:
線程A執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'); Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>線程B執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('2','2'); 等待中....然后線程A執行:
mysql> INSERT ignore into test values ('3', '3'); Query OK, 1 row affectedmysql>這時B線程檢測到死鎖,結束等待,并且自動回滾,線程A正常執行。
B檢測到死鎖:
mysql> INSERT into test values ('3', '3'),('2','2'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>========
A線程執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('9','9'),('8','8'); Query OK, 4 rows affected Records: 4 Duplicates: 0 Warnings: 0mysql>B線程執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('2','2'); 等待中然后A線程執行:
mysql> INSERT ignore into test values ('3', '3'); Query OK, 1 row affectedmysql>B線程檢測到死鎖,停止等待,自動回滾:
ysql> INSERT into test values ('3', '3'),('2','2'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>線程A死鎖:
線程A:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'); Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>線程B:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('4','4'),('2','2'); 等待中這時A線程執行:
mysql> INSERT ignore into test values ('3', '3'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>檢測到死鎖,死鎖在A線程這邊,A線程自動回滾,B線程結束等待,正常提交
mysql> INSERT into test values ('3', '3'),('4','4'),('2','2'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql>========
線程A執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'); Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>線程B執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2'); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0mysql>這時A線程執行:
mysql> INSERT ignore into test values ('3', '3'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>?A線程檢測到死鎖,并且自動回滾,釋放鎖,B線程結束等待。
猜想:誰加鎖的數據少,那么誰就檢測到死鎖,就先釋放鎖。
例如:線程A執行:
mysql> start transaction; Query OK, 0 rows affectedmysql> insert ignore into test values ('1','1'),('2','2'); Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0mysql>線程A加鎖數據:('1','1'),('2','2')
線程B:
mysql> start transaction; Query OK, 0 rows affectedmysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2'); 等待中....線程B加鎖數據:('3','3'),('4','4'),('5','5')
然后A線程執行:
mysql> insert ignore into test values ('6','6'),('7','7'),('8','8'),('9','9'),('3','3');此時A線程加鎖數據為:('1','1'),('2','2'),('6','6'),('7','7'),('8','8'),('9','9')
A線程加鎖數據多于B線程,所以B線程檢測到死鎖,主動釋放鎖,
B線程:
mysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2'); 1213 - Deadlock found when trying to get lock; try restarting transaction mysql>說明誰加鎖的數據少,那么誰就檢測到死鎖,就先釋放鎖。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的mysql insert 锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tzselect 设置时间
- 下一篇: c3p0 高并发mysql 连接slee