insert into select from加鎖順序


1、最近遇到一個小問題,由於insert into table1 select from  table2跟其他update事務造成了死鎖,於是猜想這個insert into select的加鎖順序,實驗環境如下:

(1)隔離級別:RC

(2)innodb_autoinc_lock_mode:1

(3)version: 5.6.37-log

(4)測試的兩個表結構一樣,如下:

mysql> show create table test1;
+----------+---------------------------------------------+
| Table | Create Table |
+----------+---------------------------------------------+
| test1 | CREATE TABLE `test1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`num` int(11) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31620222 DEFAULT CHARSET=utf8mb4 

2、測試sql如下

(1)session 1 :

select * from test1  where id=9 for update;

(2)session 2:

insert IGNORE  into test2 select * from  test1 where id >2 and id < 15 lock in share mode;

(3)session  3:       

insert IGNORE into test2 select 11,'9527','零零七','18888888007';  

3、測試順序

 (1)session 1開啟事務后執行sql  ------->  session 2開啟事務后執行 sql ------>session 3開啟事務后執行sql;

   可以發現,session 2、session 3 都是會被阻塞的,以下是鎖信息:

show engine innodb status
---TRANSACTION 1742170, ACTIVE 4 sec setting auto-inc lock
mysql tables in use 1, locked 1
MySQL thread id 3284, OS thread handle 0x7f20a48a5700, query id 2919013 localhost root executing
insert IGNORE into test2 select 11,'9527','零零七','18888888007'
------- TRX HAS BEEN WAITING 4 SEC FOR THIS LOCK TO BE GRANTED: 
TABLE LOCK table `test`.`test2` trx id 1742170 lock mode AUTO-INC waiting -- session 1 需要等待這個鎖
------------------
TABLE LOCK table `test`.`test2` trx id 1742170 lock mode IX
TABLE LOCK table `test`.`test2` trx id 1742170 lock mode AUTO-INC waiting


---TRANSACTION 1742169, ACTIVE 30 sec fetching rows
mysql tables in use 2, locked 2
LOCK WAIT 6 lock struct(s), heap size 1184, 13 row lock(s)
MySQL thread id 3279, OS thread handle 0x7f209e356700, query id 2919010 localhost root Sending data
insert IGNORE  into test2 select * from  test1 where id >2 and id < 15 lock in share mode
------- TRX HAS BEEN WAITING 30 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1536 page no 4 n bits 560 index `PRIMARY` of table `test`.`test1` trx id 1742169 lock mode S locks rec but not gap waiting -- session 2需要等待這個鎖

TABLE LOCK table `test`.`test2` trx id 1742169 lock mode AUTO-INC        -- session 2 持有的鎖
RECORD LOCKS space id 1536 page no 4 n bits 560 index `PRIMARY` of table `test`.`test1` trx id 1742169 lock mode S locks rec but not gap waiting


---TRANSACTION 1742168, ACTIVE 68 sec
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 3283, OS thread handle 0x7f209e51d700, query id 2919007 localhost root
TABLE LOCK table `test`.`test1` trx id 1742168 lock mode IX
RECORD LOCKS space id 1536 page no 4 n bits 560 index `PRIMARY` of table `test`.`test1` trx id 1742168 lock_mode X locks rec but not gap --session 3持有的鎖

 從鎖信息可以知道,session 3對test1表的id=9這一行加上記錄鎖,session 2先對test2表加上AUTO-INC鎖,然后等待test1表的記錄鎖,當session 3想要插入一條數據的時候因為session 2加上的AUTO-INC表級鎖,故無法插入。

    由此可知,insert into table1 select from table2首先需要申請table1的自增鎖(表級),然后再去申請table2的記錄鎖。好在table1的表級鎖是基於SQL的,一旦sql執行完即釋放自增鎖,而無需等待整個事務提交。這個加鎖順序很重要,也是下一篇產生死鎖的必要條件。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                                                            


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM