天天看點

【MySQL】mysql中的鎖機制

一、分類

mysql的鎖機制不同的存儲引擎支援不同的鎖機制,分為表級鎖、行級鎖、頁面鎖。myisam和memory存儲引擎采用的是表級鎖(table-level locking);bdb存儲引擎采用的是頁面鎖(page-level locking),但也支援表級鎖;innodb存儲引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是采用行級鎖

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。 

行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。 

頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般 

二、表級鎖

mysql的表級鎖有兩種模式:表共享讀鎖(table read lock)和表獨占寫鎖(table write lock)。 

對myisam表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;對 myisam表的寫操作,則會阻塞其他使用者對同一表的讀和寫操作。

myisam在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執行更新操作 (update、delete、insert等)前,會自動給涉及的表加寫鎖,這個過程并不需要使用者幹預,是以,使用者一般不需要直接用lock table指令給myisam表顯式加鎖。

三、行級鎖

innodb與myisam的最大不同有兩點:一是支援事務(transaction);二是采用了行級鎖。

行級鎖也支援讀鎖和寫鎖兩類。

mysql innodb引擎預設的修改資料語句:update,delete,insert都會自動給涉及到的資料加上排他鎖,select語句預設不會加任何鎖類型,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。是以加過排他鎖的資料行在其他事務種是不能修改資料的,也不能通過for update和lock in share mode鎖的方式查詢資料,但可以直接通過select …from…查詢資料,因為普通查詢沒有任何鎖機制。

innodb行鎖是通過給索引上的索引項加鎖來實作的,這一點mysql與oracle不同,後者是通過在資料塊中對相應資料行加鎖來實作的。innodb這種行鎖實作特點意味着:隻有通過索引條件檢索資料,并請求共享或排他鎖時,innodb才使用行級鎖,否則,innodb将使用表鎖! 

四、鎖的算法

record lock:單個記錄的鎖。

gap lock:間隙鎖,鎖定一個範圍,不包括記錄本身

next-key lock:gap lock+record lock

預設隔離級别(可重複讀)下,預設加的是next-key lock(為了解決幻讀問題),當索引中含有唯一屬性時(唯一索引,主鍵索引),會降級為record lock。

在讀已送出隔離級别下,加的是record lock

現在表z,有a,b兩列,a是主鍵,全表隻有一個主鍵索引。現在記錄如下:(1,1)(3,1)(5,3)(7,6)(10,8)

select * from z where b=3 for update

因為b沒有索引,是以走得是全表掃描。有因為加鎖是通過對索引加鎖實作,因為沒有走索引,所有會鎖整個表,也就是表鎖

現在表z,有a,b兩列,a是主鍵索引,b建立輔助索引。現在記錄如下:(1,1)(3,1)(5,3)(7,6)(10,8)

select * from z where a=3 for update

主鍵索引加的鎖是record lock,對記錄(3,1)加鎖

因為鎖是通過對索引加鎖實作的。是以這裡需要對主鍵索引和輔助索引加鎖,主鍵索引加的鎖會由next-key鎖退化成是record lock,輔助索引加的鎖是next-key lock,鎖定範圍是(1,3)、3、(3,6)

五、select的幾種類型

讀取的是快照版本,也就是曆史版本。普通的select就是快照讀

讀取的是最新版本。

update、delete、insert、select ...  lock in share mode、select ... for update是目前讀。

預設的可重複讀隔離級别,使用的是快照讀

讀已送出使用的是目前讀

實作原理是通過mvcc機制實作,如果讀取的行正處于update或delete中,讀操作不會去等待行上x鎖的釋放,而是去讀取行的快照資料。

mvcc,多版本并發控制技術。在 innodb 中,在每一行記錄的後面增加兩個隐藏列,記錄建立版本号和删除版本号。通過版本号和行鎖,進而提高資料庫系統并發性能。

一緻性非鎖定讀可以極大的提高并發性能

不同的事務隔離級别,讀取的快照版本是有差别的

讀已送出隔離級别,總是讀取最新的快照版本。可能會産生幻讀

可重複讀隔離級别,總是讀取事務開始後第一次讀取的快照版本。可以避免幻讀的産生

預設配置下,采用可重複讀的隔離級别,讀取資料采取的是一緻性非鎖定讀。

但是某些場景下需要對讀取操作加鎖來保證嚴格的資料一緻性,這時候可以顯式的對讀取的記錄進行加鎖:

select *** for update(對讀取記錄加x鎖)

給索引記錄加鎖,這種情況下跟update的加鎖情況是一樣的

select *** lock in share model(對讀取記錄加s鎖)  

給記錄假設共享鎖,這樣一來的話,其它事務隻能讀不能修改,直到目前事務送出

【MySQL】mysql中的鎖機制
下一篇: C語言函數

繼續閱讀