MySQL InnoDB鎖機制詳解
為什麼我們需要鎖?先別急著回答、回想一下我們在逛淘寶下訂單時的一個場景:
InnoDB 是行鎖、不存在鎖升級問題、也就是、鎖住 1 行和鎖住 1 千萬行的開銷是一樣
但是、InnoDB 行鎖仍然存在一般的鎖在高並發下所特有的"劣根性":
● 丟失更新:A的修改被B覆蓋、謂之"前浪總被後浪蓋"
● 髒讀:不同事務間、讀到未提交的數據
● 不可重復讀:同一事務、兩次讀不同
外鍵無索引是Oracle 死鎖發生的常見原因、而在InnoDB 、我趕腳、
InnoDB 是"買一送一"、並且、不要你也得要、因為、
在 InnoDB裡、會自動對外鍵添加索引、人為刪除外鍵索引會報錯
有興趣的朋友、對子表 show index from tbname; 便會發現
InnoDB 鎖有 3種類型:
● Record Lock:鎖定單條記錄
● Gap Lock:鎖定一個范圍的記錄、但不包括記錄本身
● Next-Key Lock:鎖定一個范圍的記錄、並且包含記錄本身、這是默認的鎖類型
那麼、我們該如何顯示加 InnoDB 鎖呢?有 2種方式:
● select ... lock in share mode:加 S 鎖
● select ... for update:加 X 鎖
InnoDB 鎖性能監控
[sql] view plaincopy
mysql> show status like 'innodb_row_lock_%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 23265 |
| Innodb_row_lock_time_avg | 2115 |
| Innodb_row_lock_time_max | 7401 |
| Innodb_row_lock_waits | 11 |
+-------------------------------+-------+
5 rows in set (0.00 sec)
解釋如下:
Innodb_row_lock_current_waits:當前等待鎖的數量
Innodb_row_lock_time:系統啟動到現在、鎖定的總時間長度
Innodb_row_lock_time_avg:每次平均鎖定的時間
Innodb_row_lock_time_max:最長一次鎖定時間
Innodb_row_lock_waits:系統啟動到現在、總共鎖定次數
影響 InnoDB 的幾個參數
[sql] view plaincopy
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
--設定事務隔離級別
mysql> select @@global.autocommit;
+---------------------+
| @@global.autocommit |
+---------------------+
| 1 |
+---------------------+
--自動提交
mysql> select @@global.innodb_table_locks;
+-----------------------------+
| @@global.innodb_table_locks |
+-----------------------------+
| 1 |
+-----------------------------+
--InnoDB 內部鎖定一個表
mysql> select @@global.innodb_lock_wait_timeout;
+-----------------------------------+
| @@global.innodb_lock_wait_timeout |
+-----------------------------------+
| 50 |
+-----------------------------------+
--控制等待時間
mysql> select @@global.innodb_locks_unsafe_for_binlog;
+-----------------------------------------+
| @@global.innodb_locks_unsafe_for_binlog |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
--insert into ...select 是否鎖定源表