MySQL Innodb引擎鎖總結

2022-05-04 17:30:16 字數 4101 閱讀 7866

1.鎖的目的是什麼?

innodb中利用mvcc(多版本併發控制),可以在不加鎖的情況下提高併發訪問下系統的吞吐量。但有些場景下併發訪問必須要在鎖的保護下進行,比如併發的更新。

2.鎖的分類

一般鎖是指lock。

innodb中還有不常用的一種輕量級鎖latch,latch中不存在死鎖檢測機制,適合加鎖時間較短的場景。

按相容性分類,分為s 共享鎖和x 排他鎖。s鎖之間是相容的,但x鎖不與其他鎖相容。

按粒度分類,分為表級鎖、頁鎖(innodb中好像沒有?)、行級鎖。innodb支援多粒度鎖,它允許行級鎖與表級鎖共存。

3.表鎖

mysql的myisam使用的是表鎖,而innodb有表鎖和行鎖。

innodb表級鎖包括自增鎖、意向鎖

自增鎖 auto-inc locks,用於auto_increment的自增主鍵。在innodb儲存引擎的記憶體結構中,對每個含有自增長值的表都有乙個自增長計數器。

當對表進行插入操作時,會依據自增長計數器的計數值加一賦予自增長列。為了提公升插入的效能,鎖不是事務完成後才釋放,而是完成自增長值插入的sql語句後立即釋放。

意向鎖 intention locks,表示事務有意向對錶中的某些行加鎖,分為is 意向共享鎖和ix 意向排他鎖。

is表示有意向對錶中的某些行加共享鎖,ix表示有意向對錶中的某些行加排他鎖。

意向鎖是由引擎自己維護的,使用者無法手動操作,在給資料行加共享/排他鎖之前,innodb會先給對應的表加意向鎖。

意向鎖之間是相互相容的,ix與ix之間也相互相容。另外,意向鎖也不會與行級的共享/排他鎖互斥。

意向鎖的作用是什麼?意向鎖會與表級的共享/排他鎖互斥,這裡的表級鎖指普通的表級鎖。

例如,事務a執行 select * from users where id=9 for update, 此時users表有兩把鎖,users表上的ix鎖和id=9的資料行上的排他鎖。

在事務a未commit的情況下,事務b執行lock tables users read,此時事務b檢測到事務a持有表的ix鎖,就可以得知a必然持有該表中某些行的排他鎖,因此b對users的加鎖請求就會被阻塞,就無需檢測表中每一行的資料是否存在排他鎖。

4.行級鎖

分為record lock,gap lock和next-key lock。

這裡鎖都是針對索引,通過索引來實現行鎖,而不是通過鎖住記錄。

資料庫操作使用主鍵索引時,會鎖住主鍵索引;使用非主鍵索引時,會先鎖住非主鍵索引,再鎖住主鍵索引,這樣就有可能導致死鎖(a先鎖住非主鍵索引再鎖住主鍵索引,而b先鎖住主鍵索引)。

record lock,是單個行記錄上的鎖。

gap lock,間隙鎖,鎖住乙個範圍,但是不包含記錄本身。例如事務a執行select * from users where id>5 and id<8 for update,此時就會鎖住(5,8)的區間,事務b嘗試插入id=6的操作就會被阻塞。間隙鎖之間互不衝突,它的唯一作用是防止其他事務的插入,因此加間隙s鎖和間隙x鎖沒有區別。rr隔離級別下特有。

next-key lock,record lock+gap lock,鎖住記錄本身,並且鎖定乙個範圍。

它的主要目的是,保證repeatable read(rr)的事務隔離級別下不出現phantom problem幻讀問題。

innodb預設的事務隔離級別是repeatable read,在rr中innodb行鎖預設使用next-key lock。只有當查詢的索引時唯一索引時,innodb會對next-key lock進行優化,將其降級為record lock,即僅鎖住單條索引本身而不是範圍。

當查詢的索引為輔助索引時,innodb會使用next-key lock加鎖。

5.mvcc

多版本併發控制,不加鎖的情況下支援併發查詢提高併發度。

在read committed和repeatable read隔離級別下有不同的表現。

innodb中每一行有三個隱藏列,data_trx_id表示最近修改該行資料的事務id,data_roll_ptr表示指向該行undolog段段指標,deleted_bit標記該列是否被刪除,mvcc就是通過這三個隱藏列實現。

read committed隔離級別下,每次查詢得到的是當前已經提交的資料。repeatable read級別下,查詢得到的是事務開始前的資料。

怎麼實現的?

核心內容:事務版本號,表的隱藏列,undo log和read view。通過讀取undo log的歷史版本資料,來實現不同事務擁有自己獨立的快照資料版本。

主要過程:獲得事務版本號;獲取乙個read view;查詢到資料,與read view事務版本號進行批評;不符合read view規則的從undolog裡獲取歷史版本資料;返回符合規則的資料。

read view,每個sql執行前,都會得到乙個read_view,主要儲存了當前資料庫系統中正處於活躍(沒有commit)的事務id號。

不同隔離級別下,根據不同的條件匹配read view。

rc隔離級別下,同乙個事務裡的每一次查詢都會獲得乙個新的read view副本,這樣既可能造成同乙個事務裡前後讀取資料可能不一致問題(重複讀)。

rr級別下,乙個事務裡只會獲取一次read view副本,從而保證每次查詢的資料都是不一致的。read uncommitted級別下,事務不會獲取read view副本。

事務版本號,事務開始前都會從資料庫獲取乙個自增長的事務id,可以根據事務id判斷事務的執行先後順序。

5.phantom problem幻讀問題

解決:mvcc+next-key lock?為什麼mvcc不夠?

什麼是phantom problem?

rr隔離級別下,全部使用快照讀不會存在幻讀問題,但是快照讀和當前讀混用時會存在幻讀問題,因此需要間隙鎖機制。

例項如下:

a. 事務a執行select * from t where id>3 返回id=3和4兩條記錄;

b. 事務b插入了一條id=5的資料並commit;

c.事務a執行select * from t where id>3 得到3、4兩條記錄;

d. 事務a執行update t set name='..' where id>3 更新三條記錄;

e. 事務a再次執行select * from t where id>3 得到3、4、5三條記錄。

a和c兩步均為快照讀,因此都只能讀取到兩條記錄,且不對資料加鎖。

b中插入id=5的資料,在d中是可見的,因為update中使用當前讀讀取最新commit的資料,如果不使用當前讀會有資料覆蓋問題。

因為事務a在d中對id=5的資料進行了更新,因此a中快照進行了更新,e中可以查詢到5這條記錄。

事務a中快照讀和當前讀混用,導致了幻讀問題。

如果都使用當前讀即a中使用select for update,則b中插入操作會阻塞,a中的update和select都始終只會影響兩條記錄。當前讀使用了間隙鎖,因此會阻塞b中操作。

快照讀和當前讀

快照讀是,讀取資料時,不讀取最新版本資料,而是基於歷史版本讀取的乙個快照資訊(innodb基於undo log歷史版本),快照讀可以使用普通的select讀取資料不用對錶資料進行加鎖。

當前讀是,讀取最新的資料,需要對資料加鎖。update、delete、insert、select ... lock in share mode和select ... for update 為當前讀。rc隔離級別下,只加record lock,而在rr下加record lock。

6.參考

《mysql內幕:innodb儲存引擎》-- 大名鼎鼎,但是很多東西講的不清楚,遺憾。

意向鎖各種鎖,幻讀

Mysql innodb引擎(二)鎖

專案 isixsx is相容 相容相容 不相容ix 相容相容 不相容不相容s相容 不相容相容 不相容x 不相容不相容 不相容不相容 是指 innodb 通過多版本控制的方式來讀取當前執行時間資料庫中的資料。如果,讀取的時候行正好在執行 delete 或 update 的排他操作,那讀取操作不會等待,...

MYSQL InnoDB儲存引擎 鎖

目錄 鎖的型別 行級鎖 意向鎖 一種表級鎖 一致性非鎖定讀 innodb儲存引擎的預設設定 行鎖的3種演算法 死鎖 innodb儲存引擎實現了如下兩種標準的行級鎖 1 共享鎖 s lock 允許事務讀一行資料。select column from table lock in share mode 2...

MySQL InnoDB儲存引擎 之 鎖

mysql innodb儲存引擎有七種鎖 1.自增鎖 auto inc locks 1.1 自增實現 在innodb儲存引擎記憶體結構中,對每個含有自增值的表都有乙個自增長計數器,當對其進行插入操作時,計數器會被初始化,執行如下語句得到計數器值 select max auto inc col fro...