1. 程式人生 > >關於MySQL鎖和隔離級別比較好的文章。

關於MySQL鎖和隔離級別比較好的文章。

https://segmentfault.com/p/1210000010536201/read

我所理解的髒讀,不可重複讀和幻讀。

髒讀:某個事務已更新一份資料,另一個事務在此時讀取了同一份資料,由於某些原因,前一個事務會滾了操作,導致髒讀產生。

不可重複讀:在一個事務的兩次查詢中資料不一致,可能是兩次查詢過程中插入了一個事務更新原有的資料。

幻讀:在一個事務的兩次查詢中資料筆數不一致,例如有一個事務查詢了幾行資料,而另一個卻在兩次查詢中插入了新的幾列資料。

----------------------------------------------------------------------------------

以下為原文。

我們都知道鎖的種類一般分為樂觀鎖和悲觀鎖兩種,InnoDB 儲存引擎中使用的就是悲觀鎖,而按照鎖的粒度劃分,也可以分成行鎖和表鎖。

併發控制機制

樂觀鎖和悲觀鎖其實都是併發控制的機制,同時它們在原理上就有著本質的差別;

  • 樂觀鎖是一種思想,它其實並不是一種真正的『鎖』,它會先嚐試對資源進行修改,在寫回時判斷資源是否進行了改變,如果沒有發生改變就會寫回,否則就會進行重試,在整個的執行過程中其實都沒有對資料庫進行加鎖
  • 悲觀鎖就是一種真正的鎖了,它會在獲取資源前對資源進行加鎖,確保同一時刻只有有限的執行緒能夠訪問該資源,其他想要嘗試獲取資源的操作都會進入等待狀態,直到該執行緒完成了對資源的操作並且釋放了鎖後,其他執行緒才能重新操作資源;

雖然樂觀鎖和悲觀鎖在本質上並不是同一種東西,一個是一種思想,另一個是一種真正的鎖,但是它們都是一種併發控制機制。

Optimistic-Pessimistic-Locks

樂觀鎖不會存在死鎖的問題,但是由於更新後驗證,所以當衝突頻率重試成本較高時更推薦使用悲觀鎖,而需要非常高的響應速度並且併發量非常大的時候使用樂觀鎖就能較好的解決問題,在這時使用悲觀鎖就可能出現嚴重的效能問題;在選擇併發控制機制時,需要綜合考慮上面的四個方面(衝突頻率、重試成本、響應速度和併發量)進行選擇。

鎖的種類

對資料的操作其實只有兩種,也就是讀和寫,而資料庫在實現鎖時,也會對這兩種操作使用不同的鎖;InnoDB 實現了標準的行級鎖,也就是共享鎖(Shared Lock)和互斥鎖(Exclusive Lock);共享鎖和互斥鎖的作用其實非常好理解:

  • 共享鎖(讀鎖):允許事務對一條行資料進行讀取;
  • 互斥鎖(寫鎖):允許事務對一條行資料進行刪除或更新;

而它們的名字也暗示著各自的另外一個特性,共享鎖之間是相容的,而互斥鎖與其他任意鎖都不相容:

Shared-Exclusive-Lock

稍微對它們的使用進行思考就能想明白它們為什麼要這麼設計,因為共享鎖代表了讀操作、互斥鎖代表了寫操作,所以我們可以在資料庫中並行讀,但是隻能序列寫,只有這樣才能保證不會發生執行緒競爭,實現執行緒安全。

鎖的粒度

無論是共享鎖還是互斥鎖其實都只是對某一個數據行進行加鎖,InnoDB 支援多種粒度的鎖,也就是行鎖和表鎖;為了支援多粒度鎖定,InnoDB 儲存引擎引入了意向鎖(Intention Lock),意向鎖就是一種表級鎖。

與上一節中提到的兩種鎖的種類相似的是,意向鎖也分為兩種:

  • 意向共享鎖:事務想要在獲得表中某些記錄的共享鎖,需要在表上先加意向共享鎖;
  • 意向互斥鎖:事務想要在獲得表中某些記錄的互斥鎖,需要在表上先加意向互斥鎖;

隨著意向鎖的加入,鎖型別之間的相容矩陣也變得愈加複雜:

Lock-Type-Compatibility-Matrix

意向鎖其實不會阻塞全表掃描之外的任何請求,它們的主要目的是為了表示是否有人請求鎖定表中的某一行資料

有的人可能會對意向鎖的目的並不是完全的理解,我們在這裡可以舉一個例子:如果沒有意向鎖,當已經有人使用行鎖對錶中的某一行進行修改時,如果另外一個請求要對全表進行修改,那麼就需要對所有的行是否被鎖定進行掃描,在這種情況下,效率是非常低的;不過,在引入意向鎖之後,當有人使用行鎖對錶中的某一行進行修改之前,會先為表新增意向互斥鎖(IX),再為行記錄新增互斥鎖(X),在這時如果有人嘗試對全表進行修改就不需要判斷表中的每一行資料是否被加鎖了,只需要通過等待意向互斥鎖被釋放就可以了。

鎖的演算法

到目前為止已經對 InnoDB 中鎖的粒度有一定的瞭解,也清楚了在對資料庫進行讀寫時會獲取不同的鎖,在這一小節將介紹鎖是如何新增到對應的資料行上的,我們會分別介紹三種鎖的演算法:Record Lock、Gap Lock 和 Next-Key Lock。

Record Lock

記錄鎖(Record Lock)是加到索引記錄上的鎖,假設我們存在下面的一張表 users

CREATE TABLE users(
 id INT NOT NULL AUTO_INCREMENT,
 last_name VARCHAR(255) NOT NULL,
 first_name VARCHAR(255),
 age INT,
 PRIMARY KEY(id),
 KEY(last_name),
 KEY(age)
);

如果我們使用 id 或者 last_name 作為 SQL 中 WHERE 語句的過濾條件,那麼 InnoDB 就可以通過索引建立的 B+ 樹找到行記錄並新增索引,但是如果使用 first_name 作為過濾條件時,由於 InnoDB 不知道待修改的記錄具體存放的位置,也無法對將要修改哪條記錄提前做出判斷就會鎖定整個表。

Gap Lock

記錄鎖是在儲存引擎中最為常見的鎖,除了記錄鎖之外,InnoDB 中還存在間隙鎖(Gap Lock),間隙鎖是對索引記錄中的一段連續區域的鎖;當使用類似 SELECT * FROM users WHERE id BETWEEN 10 AND 20 FOR UPDATE; 的 SQL 語句時,就會阻止其他事務向表中插入 id = 15 的記錄,因為整個範圍都被間隙鎖鎖定了。

間隙鎖是儲存引擎對於效能和併發做出的權衡,並且只用於某些事務隔離級別。

雖然間隙鎖中也分為共享鎖和互斥鎖,不過它們之間並不是互斥的,也就是不同的事務可以同時持有一段相同範圍的共享鎖和互斥鎖,它唯一阻止的就是其他事務向這個範圍中新增新的記錄

Next-Key Lock

Next-Key 鎖相比前兩者就稍微有一些複雜,它是記錄鎖和記錄前的間隙鎖的結合,在 users 表中有以下記錄:

+------+-------------+--------------+-------+
| id | last_name | first_name | age |
|------+-------------+--------------+-------|
| 4 | stark | tony | 21 |
| 1 | tom | hiddleston | 30 |
| 3 | morgan | freeman | 40 |
| 5 | jeff | dean | 50 |
| 2 | donald | trump | 80 |
+------+-------------+--------------+-------+

如果使用 Next-Key 鎖,那麼 Next-Key 鎖就可以在需要的時候鎖定以下的範圍:

(-∞, 21]
(21, 30]
(30, 40]
(40, 50]
(50, 80]
(80, ∞)

既然叫 Next-Key 鎖,鎖定的應該是當前值和後面的範圍,但是實際上卻不是,Next-Key 鎖鎖定的是當前值和前面的範圍。

當我們更新一條記錄,比如 SELECT * FROM users WHERE age = 30 FOR UPDATE;,InnoDB 不僅會在範圍 (21, 30] 上加 Next-Key 鎖,還會在這條記錄後面的範圍 (30, 40] 加間隙鎖,所以插入 (21, 40] 範圍內的記錄都會被鎖定。

Next-Key 鎖的作用其實是為了解決幻讀的問題,我們會在下一節談事務的時候具體介紹。

死鎖的發生

既然 InnoDB 中實現的鎖是悲觀的,那麼不同事務之間就可能會互相等待對方釋放鎖造成死鎖,最終導致事務發生錯誤;想要在 MySQL 中製造死鎖的問題其實非常容易:

Deadlocks

兩個會話都持有一個鎖,並且嘗試獲取對方的鎖時就會發生死鎖,不過 MySQL 也能在發生死鎖時及時發現問題,並保證其中的一個事務能夠正常工作,這對我們來說也是一個好訊息。

事務與隔離級別

在介紹了鎖之後,我們再來談談資料庫中一個非常重要的概念 —— 事務;相信只要是一個合格的軟體工程師就對事務的特性有所瞭解,其中被人經常提起的就是事務的原子性,在資料提交工作時,要麼保證所有的修改都能夠提交,要麼就所有的修改全部回滾。

但是事務還遵循包括原子性在內的 ACID 四大特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和永續性(Durability);文章不會對這四大特性全部展開進行介紹,相信你能夠通過 Google 和資料庫相關的書籍輕鬆獲得有關它們的概念,本文最後要介紹的就是事務的四種隔離級別。

幾種隔離級別

事務的隔離性是資料庫處理資料的幾大基礎之一,而隔離級別其實就是提供給使用者用於在效能和可靠性做出選擇和權衡的配置項。

ISO 和 ANIS SQL 標準制定了四種事務隔離級別,而 InnoDB 遵循了 SQL:1992 標準中的四種隔離級別:READ UNCOMMITEDREAD COMMITEDREPEATABLE READ 和 SERIALIZABLE;每個事務的隔離級別其實都比上一級多解決了一個問題:

  • RAED UNCOMMITED:使用查詢語句不會加鎖,可能會讀到未提交的行(Dirty Read);
  • READ COMMITED:只對記錄加記錄鎖,而不會在記錄之間加間隙鎖,所以允許新的記錄插入到被鎖定記錄的附近,所以再多次使用查詢語句時,可能得到不同的結果(Non-Repeatable Read);
  • REPEATABLE READ:多次讀取同一範圍的資料會返回第一次查詢的快照,不會返回不同的資料行,但是可能發生幻讀(Phantom Read);
  • SERIALIZABLE:InnoDB 隱式地將全部的查詢語句加上共享鎖,解決了幻讀的問題;

MySQL 中預設的事務隔離級別就是 REPEATABLE READ,但是它通過 Next-Key 鎖也能夠在某種程度上解決幻讀的問題。

Transaction-Isolation-Matrix

接下來,我們將資料庫中建立如下的表並通過個例子來展示在不同的事務隔離級別之下,會發生什麼樣的問題:

CREATE TABLE test(
 id INT NOT NULL,
 UNIQUE(id)
);

髒讀

當事務的隔離級別為 READ UNCOMMITED 時,我們在 SESSION 2 中插入的未提交資料在 SESSION 1 中是可以訪問的。

Read-Uncommited-Dirty-Read

不可重複讀

當事務的隔離級別為 READ COMMITED 時,雖然解決了髒讀的問題,但是如果在 SESSION 1 先查詢了一個範圍的資料,在這之後 SESSION 2 中插入一條資料並且提交了修改,在這時,如果 SESSION 1 中再次使用相同的查詢語句,就會發現兩次查詢的結果不一樣。

Read-Commited-Non-Repeatable-Read

不可重複讀的原因就是,在 READ COMMITED 的隔離級別下,儲存引擎不會在查詢記錄時新增間隙鎖,鎖定 id < 5 這個範圍。

幻讀

重新開啟了兩個會話 SESSION 1 和 SESSION 2,在 SESSION 1 中我們查詢全表的資訊,沒有得到任何記錄;在 SESSION 2 中向表中插入一條資料並提交;由於 REPEATABLE READ 的原因,再次查詢全表的資料時,我們獲得到的仍然是空集,但是在向表中插入同樣的資料卻出現了錯誤。

Repeatable-Read-Phantom-Read

這種現象在資料庫中就被稱作幻讀,雖然我們使用查詢語句得到了一個空的集合,但是插入資料時卻得到了錯誤,好像之前的查詢是幻覺一樣。

在標準的事務隔離級別中,幻讀是由更高的隔離級別 SERIALIZABLE 解決的,但是它也可以通過 MySQL 提供的 Next-Key 鎖解決:

Repeatable-with-Next-Key-Lock

REPERATABLE READ 和 READ UNCOMMITED 其實是矛盾的,如果保證了前者就看不到已經提交的事務,如果保證了後者,就會導致兩次查詢的結果不同,MySQL 為我們提供了一種折中的方式,能夠在 REPERATABLE READ 模式下加鎖訪問已經提交的資料,其本身並不能解決幻讀的問題,而是通過文章前面提到的 Next-Key 鎖來解決。

相關推薦

關於MySQL隔離級別比較文章

https://segmentfault.com/p/1210000010536201/read我所理解的髒讀,不可重複讀和幻讀。髒讀:某個事務已更新一份資料,另一個事務在此時讀取了同一份資料,由於某些原因,前一個事務會滾了操作,導致髒讀產生。不可重複讀:在一個事務的兩次查詢

隔離級別--mysql sql 20170526更新

刪掉了之前的部落格(摘抄,不精準,理解欠佳) 資料庫隔離級別: 資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個級別可以逐個解決髒讀、不可重複讀、幻

mysql 開發進階篇系列 12 問題(隔離級別的差異)

padding 排它 改變 level order 並發 aci delete 恢復 1. innodb在不同隔離級別下的一致性讀及鎖的差異   不同的隔離級別下,innodb處理sql 時采用的一致性讀策略和需要的鎖是不同的,同時,數據恢復和復制機制的特點,也對一些sql

MySQL學習之事務及其四大特性隔離級別

事務 定義: 事務是指資料庫中的一組邏輯操作,這個操作的特點就是在該組邏輯中,所有的操作要麼全部成功,要麼全部失敗。在各個資料具有特別緊密的聯絡時,最好是使用資料庫的事務來完成邏輯處理。 說的通俗點就是,我們執行一個事件時,光靠簡簡單單的一句sql語句是無法完成的,這時候我們

MySQL事務的隔離級別ACID

導致 持久 完成 數據 實現 容易 規則 除了 一份 在MySQL中隔離性有4種級別, read-uncommitted (讀未提交 ;會產生臟讀,不可重復讀,幻讀)在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的性能也不比

粗談MySQL事務的特性隔離級別

網上對於此類的文章已經十分飽和了,那還寫的原因很簡單——作為自己的理解筆記。 前言 ​  此篇文章作為自己學習MySQL的一些個人理解,使用的引擎是InnoDb。首先先講講事務的概念,在《高效能MySQL》第三版中其對事務的描述是這樣的: 事務就是一組原子性的SQL查詢,或者說一個獨立的工作單元。如果資

mysql的事務隔離級別

too con jpg 級別 tran 開啟 數據行 修改 ges 原文地址:http://www.cnblogs.com/snsdzjlz320/p/5761387.html [Mysql]——通過例子理解事務的4種隔離級別 SQL標準定義了4種隔離級別,包括了一

MySql四種隔離級別

serial 改變 共享 表結構 競爭 隔離級別 處理 nal 完全 什麽是事務 事務是應用程序中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要麽全部成功,要麽一個都不做。 事務的結束有兩種

mysql 不同事務隔離級別

結果 讀取 般的 lec 不同的 新增 比較 一次 基礎 repeatable read 在同一事務中,同一查詢多次進行時候,由於其他插入操作(insert)的事務提交,導致每次返回不同的結果集。 標準的repeatable read是允許幻讀的,因為這一級別只在讀取過的紀

MySQL事務(一):InnoDBMySQL 官方文檔粗翻)

空間索引 系統 聚集索引 rds update 能夠 conf 沒有 得到   // 寫在前面,實際上,數據庫加鎖的類型和範圍受到多種因素的影響,例如數據庫隔離等級,SQL語句,是否使用主鍵、索引等等。可以查看博文: http://www.cnblogs.com/zhaoy

MySQL--REPEATABLE-READ隔離級別下讀取到的“重復數據”

屬於 兩個 客戶端 並發控制 存在 讀取 select 執行 create 在MySQL中,使用MVCC來實現REPEATABLE-READ隔離級別,由於SELECT操作不會對數據加鎖,其他回話可以修改當前回話所讀取過的數據而不會被阻塞,因此讀寫不沖突。 在MVCC並發控

數據庫事務特性隔離級別

read 事務隔離 mil 對數 alt tro 取數 部分 失敗 事務 一組業務操作,要麽全部成功,要麽全部不成功。 ----------------事務的特性-------------- 原子性:一個事務是一個整體,不可分割,事務中的操作要麽都成功,要麽都失敗。

談談MySQL的事務隔離級別

提交 執行過程 操作 dnf 情況 以及 讀取 int 並且 這篇文章能夠闡述清楚跟數據庫相關的四個概念:事務、數據庫讀現象、隔離級別、鎖機制   一、事務 先來看下百度百科對數據庫事務的定義:   作為單個邏輯單元執行一系列操作,要麽完全執行,要麽完全不執行。事務處理可以

數據庫 之 事務控制隔離級別

可能 處理 eas 獨立 ble space 銷毀 實現 rac 1 概述事務是指一組原子性的SQL查詢、或者是一個或多個SQL語句組成的獨立工作單元;MyISAM不流行的原因很大是因為其不支持事務的處理功能。2 事務日誌事務日誌定義屬性,有些參數可以運行時修改,寫入在

事務的特性隔離級別

持久性 atom gre 永久 commit nco 持久 問題 city 1.事務的特性ACID 1)原子性(Atomicity)原子性是指事務是一個不可分割的工作單位,事務中的操作要麽都發生,要麽都不發生。 2)一致性(Consistency)一個事務中,事務前後

記一個mysql環境RR隔離級別轉換成RC的問題

mysql 事務隔離級別 RR RC先了解RR(REPEATABLE-READ)和RC(READ-COMMITTED)的區別.RR隔離級別增加了間隙鎖,避免了幻讀,並且阻止了不可重復讀,讓同一個事務裏面的查詢和修改都是一致的.mysql默認的隔離級別就是RR.雖然說RC隔離級別在同一個事務內會存在查詢出不同數

mysql事務以及隔離級別

系統 www. 情況 ria 人員管理 等待 UNC 完整 執行過程 mysql事務以及隔離級別 1. 簡介 MySQL 事務主要用於處理操作量大,復雜度高的數據。比如說,在人員管理系統中,你刪除一個人員,你即需要刪除人員的基本資料,也要刪除和該人員相關的信息,如信箱,文章

Mysql ACID與隔離級別

detail https itl lan http -i log blank cnblogs 參考: https://blog.csdn.net/csdnxingyuntian/article/details/57081233 https://www.cnblogs.com

MySQL的事物隔離級別

read uncommitted read committed repeatable read serializable  查詢事物的隔離級別 SELECT @@GLOBAL.tx_isolation, @@tx_isolation; SELECT @@tx_i

資料庫的事物隔離級別

事物的特性 1. 原子性(Atomicity):事務中包含的所有操作,要麼一次性完成,要麼失敗後,全部回滾。 2. 一致性(Consistency):事務提交前和事務提交後,都必須是一致的。 3. 隔離性(Isolation):事務與事務之間是隔離的,多個併發事務不能互相影響。