剖析MySQL InnoDB引擎的行鎖表鎖,怎樣利用鎖解決事務併發問題

在正式講解各種鎖之前,先來預習事務的四種隔離級別,因爲MySQL事務隔離級別不同,所用到的鎖也有差別。各種事務隔離級別可以對應解決不同類型的事務併發帶來的問題,事務隔離級別越高,可以解決的事務併發問題越多,同時性能事務性能也就越低,所以並非事務隔離級別越高越好。

一、事務併發帶來的問題

1、髒讀:髒讀發生在一個事務A讀取了被另一個事務B修改,但是還未提交的數據。假如B回退,則事務A讀取的是無效的數據。

2、不可重複讀:在基於鎖的並行控制方法中,如果在執行select時不添加讀鎖,就會發生不可重複讀問題。

3、幻讀:幻讀發生在當兩個完全相同的查詢執行時,第二次查詢所返回的結果集跟第一個查詢不相同。

二、事務四種隔離級別

1、Read Uncommitted(未提交讀):事務未提交對其他事務也是可見的,此時可能發生髒讀。

2、Read Committed(提交讀):一個事務開始之後,只能看到自己提交的事務所做的修改,解決了髒讀問題,但可能會發生不可重複讀問題。

3、Repeatable Read (可重複讀) :在同一個事務中多次讀取同樣的數據結果是一樣的,解決了不可重複讀問題,但未能解決幻讀的問題。

4、Serializable(串行化):最高的隔離級別,通過強制事務的串行執行。

三、Innodb引擎行鎖、表鎖

鎖是用於管理不同事務對共享資源的併發訪問。那麼行鎖到底鎖住了什麼,InnoDB的行鎖是通過給索引上的索引項加鎖來實現的。只有通過索引條件進行數據檢索,InnoDB才使用行級鎖,否則InnoDB將使用表鎖(鎖住索引的所有記錄)。

常見的MySQL InnoDB鎖類型包括:共享鎖(S鎖、行鎖)、排它鎖(X鎖、行鎖)、意向共享鎖(IS鎖、表鎖)、意向排它鎖(IX鎖、表鎖)、記錄鎖(Record Locks)、間隙鎖(Gap Locks)、臨鍵鎖(Next-key Locks)。

共享鎖就是多個事務對於同一數據可以共享一把鎖,都能訪問到數據,但是隻能讀不能修改。排他鎖不能與其他鎖並存,如一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的鎖(共享鎖、排他鎖),只有該獲取了排他鎖的事務是可以對數據行進行讀取和修改。

下面寫一個簡單的示例,DDL如下:

CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
 `name` varchar(32) DEFAULT NULL COMMENT '姓名',
 `age` int(8) DEFAULT NULL COMMENT '年齡',
 `lastUpdate` datetime DEFAULT NULL COMMENT '更新時間',
 PRIMARY KEY (`id`),
 UNIQUE KEY `user_name` (`name`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人員信息';

set session autocommit=OFF
update user set lastUpdate=now() where id=1;

執行上述語句時,Innodb引擎會自動添加排它鎖(X鎖),同時對該表添加意向排它鎖(IX),告訴其它事務該表上有排它鎖,不能再對該表進行表鎖操作。

此時執行語句update user set lastUpdate=now() where name='王飛';可以論證上述結論,由於user表沒有基於name的索引,所有執行該語句時會對全表進行鎖定(表鎖),在對錶user進行表鎖時,會發現該表上有意向排它鎖(IX)存在,所以此時進行表鎖失敗,只能進行事務等待。

臨鍵鎖Next-key Lock,當sql執行按照索引進行數據的檢索時,查詢條件爲範圍查找(between and、<、>等)並有數據命中則此時SQL語句加上的鎖爲Next-key locks,鎖住索引的記錄+區間。爲了解決幻讀問題,也就是在進行範圍查詢時,使用臨鍵鎖把相鄰的下一個區間鎖住,進而防止了新插入數據。Next-key Lock = Gap Lock + Record Lock。

間隙鎖Gap Locks,當sql執行按照索引進行數據的檢索時,範圍查詢或等值查詢的數據不存在,這時SQL語句加上的鎖即爲Gap locks,鎖住索引不存在的區間。

臨鍵鎖Next-key Locks,當sql執行按照唯一性(Primary key、Unique key)索引進行數據的檢索時,查詢條件等值匹配且查詢的數據是存在,這時SQL語句加上的鎖即爲記錄鎖Record locks。

四、怎樣利用鎖解決事務併發問題

1、利用鎖怎麼解決髒讀:事務B對數據進行更新操作時加上排他鎖(x鎖),此時事務A不可讀數據,由此解決了事務A髒讀問題。

2、利用鎖怎麼解決不可重複讀:事務A在進行讀取操作時加上共享鎖(s鎖),此時事務B不可修改數據庫,由此解決了事務A不可重複讀問題。

3、利用鎖怎麼解決幻讀:事務A範圍操作時加上Next-key鎖,鎖住記錄和區間,事務B無法插入新的數據,由此解決了事務A幻讀問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章