(10)MySQL進階篇SQL優化(InnoDB鎖-間隙鎖)


1.概述

當我們用范圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;對於鍵值在條件范圍內但並不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。

2.InnoDB存儲引擎的間隙鎖阻塞例子

先創建一個間隙臨時表,ID為主鍵自增:

MySQL [(none)]> CREATE TABLE goods. tab_gap (ID INT NOT NULL auto_increment,Name VARCHAR(50),PRIMARY KEY(ID));
Query OK, 0 rows affected (0.02 sec)

先插入五行數據:

MySQL [(none)]> INSERT INTO goods.tab_gap (ID,`Name`) VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e');
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

示例:

session_1

session_2

1)查詢事務隔離級別是否是可重復讀

1查詢事務隔離級別是否是可重復讀

MySQL [(none)]> SHOW VARIABLES LIKE 'transaction_isolation%';

+-----------------------+-----------------+

| Variable_name         | Value                      |

+-----------------------+-----------------+

| transaction_isolation | REPEATABLE-READ |

+-----------------------+-----------------+

1 row in set (0.01 sec)
MySQL [(none)]> SHOW VARIABLES LIKE 'transaction_isolation%';

+-----------------------+-----------------+

| Variable_name         | Value                      |

+-----------------------+-----------------+

| transaction_isolation | REPEATABLE-READ |

+-----------------------+-----------------+

1 row in set (0.01 sec)

2先設置事務T1提交類型為事務非自動提交。

2先設置事務T2提交類型為事務非自動提交。

MySQL [(none)]> SET AUTOCOMMIT=0;

Query OK, 0 rows affected (0.00 sec)
MySQL [(none)]> SET AUTOCOMMIT=0;

Query OK, 0 rows affected (0.00 sec)

3為當前session_1事務中Name=f’不存在的記錄行加排他鎖。

 

 

MySQL [(none)]> SELECT * FROM goods.tab_gap WHERE `Name`='f' FOR UPDATE;

Empty set (0.00 sec)

 

 

3如果這時session_2插入ID=6的記錄行(注意:這條記錄並不存在),也會出現鎖等待。

MySQL [(none)]> INSERT INTO goods.tab_gap (ID,`Name`) VALUES (6,'f');

阻塞...

4回滾事務。

 

 

MySQL [(none)]> ROLLBACK;

Query OK, 0 rows affected (0.00 sec)

 

 

4由於session_1回滾后釋放了間隙鎖, 所以當前session_2可以獲得鎖並成功插入記錄。

MySQL [(none)]> INSERT INTO goods.tab_gap (ID,`Name`) VALUES (6,'f');

Query OK, 1 row affected (38.41 sec)

 

 

5提交事務,釋放鎖。

MySQL [(none)]> COMMIT;

Query OK, 0 rows affected (0.00 sec)

4為當前session_1事務中ID>4范圍的記錄行加排他鎖。

 

 

MySQL [(none)]> SELECT * FROM goods.tab_gap WHERE ID>4 FOR UPDATE;

+----+------+

| ID | Name |

+----+------+

|  5 | e    |

|  6 | f    |

+----+------+

2 rows in set (0.00 sec)

 

 

6為當前session_2事務中ID=5的記錄行加排他鎖,發生阻塞。

MySQL [(none)]> SELECT * FROM goods.tab_gap WHERE ID>5 FOR UPDATE;

阻塞...

從示例中可以看到,在Mysql默認事務隔離級別下,如果在相等的條件中給一個不存在的記錄行加鎖,InnoDB也會使用間隙鎖,不然session_1會出現幻讀(session_1事務中能查詢到session_2插入ID=6的記錄行)。而當我們在ID>4范圍條件內加鎖,InnoDB不僅會對符合條件的ID值為5、6的記錄行加鎖,也會為大於6以上的記錄行加間隙鎖(不管數據是否存在)。

3.總結

InnoDB使用間隙鎖的目的,一方面是為了防止幻讀,以滿足相關隔離級別的要求。另外一方面,是為了滿足其恢復和復制的需要。有關其恢復和復制對鎖機制的影響,以及不同隔離級別下InnoDB使用間隙鎖的情況,在后續的章節中會做進一步介紹。很顯然,在使用范圍條件檢索並鎖定記錄時,InnoDB這種加鎖機制會阻塞符合條件范圍內鍵值的並發插入,這往往會造成嚴重的鎖等待!因此,在實際應用開發中,尤其是並發插入比較多的應用程序,我們要盡量優化業務邏輯,盡量使用相等條件來訪問更新數據,避免使用范圍條件。還要特別說明的是,InnoDB除了通過范圍條件加鎖時使用間隙鎖外,如果使用相等條件請求給一個不存在的記錄加鎖,InnoDB也會使用間隙鎖!

參考文獻:
深入淺出MySQL大全


免責聲明!

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



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