InnoDB 存儲引擎 lock 的對象是事務,用來鎖定的是數據庫中的對象,如表、頁、行,而且通常 lock 的對象僅在事務 commit 或 rollback 後進行釋放(不一樣事務隔離級別釋放的時間可能不一樣)。算法
InnoDB 存儲引擎實現了以下兩種標準的行級鎖,其中,X 鎖與任何的鎖都不兼容,而 S 鎖僅和 S 鎖兼容(兼容指對同一記錄行的兼容性狀況)sql
InnoDB 存儲引擎除了行鎖之外,還有表鎖,一般也稱爲意向鎖,其設計目的主要是爲了在一個事務中揭示下一行將被請求的鎖類型。其支持兩種意向鎖:數據庫
經過 information_schema 架構下的 INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS 三張表,用戶能夠更簡單的監控當前事務並分析可能存在的鎖問題。架構
SELECT * FROM information_schema.INNODB_TRX; SELECT * FROM information_schema.INNODB_LOCKS; SELECT * FROM information_schema.INNODB_LOCK_WAITS;
InnoDB 存儲引擎有三種行鎖的算法,其分別是:併發
Record Lock 老是會去鎖住索引記錄,InnoDB 存儲引擎會使用聚簇索引來進行鎖定。優化
Gap Lock 的做用是爲了阻止多個事務將記錄插入到同一個範圍內,由於這會致使幻讀問題(phantom Problem)的產生,用戶能夠經過如下兩種方式來顯式地關閉 Gap Lock:設計
Next-Key Lock 是結合了 Gap Lock 和 Record Lock 的一種索引算法,這種鎖定技術,不止鎖定記錄自己,還鎖定一個範圍。code
InnoDB 對於行的查詢默認是採用 Next-Key Lock 算法,當查詢的索引含有惟一屬性時(主鍵索引、惟一索引),InnoDB 存儲引擎會對 Next-Key Lock 進行優化,將其降級爲 Record Lock;而對於輔助索引,不只會對索引列加 Record Lock ,還會對索引列先後的鍵值範圍加上 Gap Lock。orm
Phantom Problem:幻讀問題,指在同一事務下,連續執行兩次一樣的 SQL 語句可能致使不一樣的結果,第二次的 SQL 語句可能會返回以前不存在的行。對象
select * from students where id = 20 for update;
select * from students where num = 135 for update;
select * from students where score= 91 for update;
select * from students where age = 22 for update;
Dirty Read 髒讀:一個事務讀到了另外一個未提交的事務寫的數據,這顯然違反了數據庫的隔離性。
Non-Repeatable Read 不可重複讀:一個事務內屢次讀取同一數據集合,可能兩次讀到的數據是不同的。不可重複讀和髒讀的區別是:髒讀是讀到未提交的數據,而不可重複讀讀到的倒是已經提交的數據,這顯然違反了數據庫的一致性。
Phantom Problem 幻讀 :幻讀問題,指在同一事務下,連續執行兩次一樣的 SQL 語句可能致使不一樣的結果,第二次的 SQL 語句可能會返回以前不存在的行。幻讀是比不可重複讀高一個級別的錯誤,讀取同一條數據發現跟剛纔是同樣的,只有讀取一堆數據發現突然多了一個,或者少了一個,像是產生了幻覺。
Lost Update 更新丟失
a. 第一類更新丟失,回滾覆蓋:撤消一個事務時,在該事務內的寫操做要回滾,把其它已提交的事務寫入的數據覆蓋了。
b. 第二類更新丟失,提交覆蓋:提交一個事務時,寫操做依賴於事務內讀到的數據,讀發生在其餘事務提交前,寫發生在其餘事務提交後,把其餘已提交的事務寫入的數據覆蓋了。這是不可重複讀的特例。
爲了解決多個事務併發會引起的鎖問題,數據庫系統提供了四種事務隔離級別供用戶選擇。
爲何 MYSQL 默認使用 Repeatable Read 隔離級別?這跟數據庫的主從複製有關,MYSQL 的主從複製是基於 binlog 複製的,而 binlog 有三種格式,分別爲:
那 MYSQL 在 5.0 這個版本之前,binlog 只支持 statement 這種格式!而這種格式在讀已提交(Read Commited)這個隔離級別下主從複製是有 bug 的,所以 Mysql 將可重複讀(Repeatable Read)做爲默認的隔離級別。
怎麼解決 Read Committed 隔離級別下,主從複製有問題的 bug?首先得解釋下這個 bug,在 master 上執行的順序爲先刪後插,若此時 binlog 爲 statement 格式,它記錄的順序爲先插後刪,slave 同步的是 binglog,所以 slave 執行的順序和主機不一致,就會出現主從不一致,怎麼解決這個 bug 呢?
在 InnoDB 存儲引擎中,參數 innodb_lock_wait_timeout
用來控制等待得時間(默認是 50 秒),innodb_rollback_on_timeout
用來設定是否在等待超時時對進行中的事務進行回滾操做(默認是 OFF,表明不回滾)
InnoDB 存儲引擎在大部分狀況下都不會對異常進行回滾(死鎖除外),所以用戶必須判斷是否須要 COMMIT 仍是 ROLLBACK,以後再進行下一步的操做。
InnoDB 存儲引擎經過 wait-for graph(等待圖)的方式來進行死鎖檢測,wait-for graph 是一種較爲主動的死鎖檢測機制,在每一個事務請求鎖併發生等待時都會判斷是否存在迴路,若存在則有死鎖,一般來講 InnoDB 存儲引擎選擇回滾 undo 量最小的事務。
InnoDB 存儲引擎不存在鎖升級的問題,由於其不是根據每一個記錄來產生行鎖的,相反,其根據每一個事務訪問的每一個頁對鎖進行管理的,採用的是位圖的方式。所以無論一個事務鎖住頁中的一個記錄仍是多個記錄,其開銷一般是一致的。