淺談MySQL的事務隔離級別

  但願這篇文章可以闡述清楚跟數據庫相關的四個概念:事務、數據庫讀現象、隔離級別、鎖機制數據庫

1、事務

先來看下百度百科對數據庫事務的定義:併發

  做爲單個邏輯單元執行一系列操做,要麼徹底執行,要麼徹底不執行。事務處理能夠確保除非事務性單元內的全部操做都成功完成,不然不會永久更新面向數據的資源。性能

事務有四個屬性,稱爲ACID屬性:spa

一、原子性(Atomicity):事務是一個原子單位,要麼所有執行,要麼所有不執行。3d

二、一致性(Consistent):事務的開始和結束,數據都必須保持一致狀態。對象

三、隔離性(isolation):數據庫系統提供隔離機制,保證併發事務之間是互相不干擾的。也就意味着事務處理過程當中的中間狀態對其餘的事務是透明的。blog

四、持久性(Durable):事務完成以後,對數據的修改是永久性的,即便出現系統故障也可以保持事務

 

事務是一系列SQL語句的集合,若是沒有事務,會出現什麼問題?或者說SQL只能一條一條的單個執行,會出現什麼問題?ci

這個很簡單,若是沒有事務,咱們平時生活中的銀行轉帳就沒法操做。資源

2、數據庫讀現象

  ACID屬性裏面有一個是隔離級別,即併發事務之間互相不干擾。互相不干擾只是一個終極狀態,且須要消耗巨大的性能。在咱們實際應用過程當中,是存在很大的灰度空間的:隔離級別有程度的區分。因此若是隔離程度控制的比較弱的話,就會產生髒讀不可重複讀以及幻讀的現象。

一、髒讀

事務T1修改某個字段的值,而後事務T2讀取該值,此後T1撤銷了對該字段的更新,或者更新成另外的值才commit到數據庫中,這樣T2讀取的數據是無效的或者錯誤的。致使T2依據髒數據所作的操做也是錯誤的。

---------思聰同窗中午去食堂吃飯,看到窗邊的座位被如花同窗佔有了,思聰認爲這個座位已經被佔有了,就轉身去找其餘的座位。不料,如花同窗起身離開了。事實是:如花並非吃飯,而是臨時坐在那裏等她的約會對象,只是臨時小坐一會,並無真正「commit」。

二、不可重複讀

在數據庫訪問中,一個事務範圍內的兩次相同的查詢卻返回了不一樣的數據。

事務T1讀取某一數據,事務T2讀取並修改了該數據,T1爲了對讀取值進行驗證而從新讀取,卻發現獲得了不一樣的結果。

---------思聰同窗中午去食堂吃飯,看到窗邊的座位是空的,便屁顛屁顛的跑去打飯,回來後卻發現這個座位被如花同窗搶去了。

三、幻讀

幻讀解決了不可重複讀的問題,即在同一個事務範圍內,兩次相同的查詢結果是相同的。可是能夠新增表中的數據記錄。

幻讀是指事務T1對錶中的數據進行修改,假設修改涉及了表中所有的數據行,同時第二個事務也修改這個表中的數據,這種修改是向表中插入一條新的數據。後面就會出現操做了T1事務的用戶發現表中還有沒有修改的數據行,彷彿出現了幻覺同樣。

--------思聰同窗中午去食堂吃飯,看到窗邊的座位是空的,便屁顛屁顛的跑去打飯,回來後窗邊的座位仍是空的,便很高興坐上去準備開始吃飯,這時候卻發現如花同窗搬了一個小板凳坐在旁邊狼吞虎嚥,思聰頓時沒有了胃口。

若是須要解決髒讀、不可重複讀、幻讀等這些數據庫讀現象,就必須相應提升事務的隔離級別。可是數據庫的隔離級別越高,對應的併發能力就越弱,性能也就相應的越差,因此咱們還需根據具體的應用場景去權衡。

3、事務隔離級別

一、未提交讀

事務的最低隔離級別,在這種隔離級別下,一個事務能夠讀取另一個事務未提交的數據。

數據庫鎖實現原理:

事務T在讀數據的時候並未對數據進行加鎖,事務T在修改數據的時候對數據增長行級共享鎖

T1在讀取數據時,T2能夠對相同數據進行讀取、修改。由於T1沒有進行任何鎖操做;當T2對記錄進行修改時,T1再次讀取數據能夠讀取到T2修改後的數據。由於T2對數據進行修改只增長了行級共享鎖,T1能夠再增長共享讀鎖進行數據讀取(儘管T2沒有提交事務)

如上所述,這種隔離級別,會致使髒讀現象

二、已提交讀

在一個事務修改數據過程當中,若是事務沒有進行提交,其餘事務不能讀取該數據

數據庫鎖實現原理:

事務T在讀取數據時增長行級共享鎖,讀取一旦結束,當即釋放;事務T在修改數據時增長行級排他鎖,直到事務結束才釋放。

T1在讀取數據的過程當中,T2也能夠對相同數據進行讀取,可是不能進行修改(T1增長的是共享鎖,T2也能夠增長共享鎖,可是不能增長排他鎖)。T1讀取結束後,會當即釋放共享鎖,這時T2能夠增長排他鎖,對數據進行修改,而此時T1既不能對數據進行讀取也不能進行修改,直到T2事務結束。

如上所述,這種隔離級別,解決了髒讀問題,可是不能解決不可重複讀現象。

三、可重複讀

事務T在數據讀取時,必須增長行級共享鎖,直到事務結束;事務T在修改數據過程當中,必須增長行級排他鎖,直到數據結束。

數據庫鎖實現原理:

T1在讀取數據的過程當中,T2也能夠對相同數據進行讀取,可是不能進行修改(T1增長的是共享鎖,T2也能夠增長共享鎖,可是不能增長排他鎖)。直到T1事務結束後,纔會釋放共享鎖,這時T2才能夠增長排他鎖,對數據進行修改。

如上所述,這種隔離級別,解決了不可重複讀現象,可是這種隔離級別解決不了幻讀的問題:

T1進行查詢,讀取了10條記錄,並對十條記錄增長了行級鎖,此時T2是沒法對這10行數據進行修改操做的,可是因爲沒有表級鎖,它能夠增長一條知足T1查詢條件的記錄。隨後T1在進行查詢時,會發現雖然10條記錄沒有改變,可是忽然多了一條記錄。

四、序列化

產生幻讀是因爲沒有進行範圍查詢時沒有增長範圍鎖。

 數據庫鎖實現原理:

 事務T在讀取數據時,必須先增長表級共享鎖,直到事務結束才釋放;事務T在修改數據時,必須先增長表級排他鎖,直到事務結束才釋放。

T1在讀取A表時,增長了表級共享鎖,此時T2也能夠讀取A表,可是不能進行任何數據的修改,直到T1事務結束。隨後T2能夠增長對A表的表級排他鎖,此時T1不能讀取A表中的任何數據,更不能進行修改。

如上所述,可序列化解決了髒讀、不可重複讀、幻讀等讀現象,可是隔離級別愈來愈高的同時,在併發性上也就愈來愈低。

4、事務操做實踐 

默認狀況下,MYSQL是自動提交的,也就意味着平時咱們執行一條update語句時,MYSQL是自動幫咱們提交的,儘快咱們沒有顯示執行commit命令。可是這種只適用於單條SQL的執行。

若是咱們想要同時執行多條SQL,而且執行過程當中有SQL執行異常,須要回滾前面已經成功執行的SQL或者最終想回滾所有,則必須顯示的使用事務。

一、開始一項事務:start tr ansaction或者begin;

二、提交事務:commit;

三、回滾事務:rollback;

四、事務提交以後的操做:chain;

五、事務回滾以後的操做:release;

六、修改當前鏈接的提交方式:set autocommit;若是設置了set autocommit=0,則設置以後全部的事務都須要顯式的經過命令來進行提交或者回滾。

查詢當前會話的事務隔離級別

查詢當前系統的事務隔離級別

修改當前會話的事務隔離級別

 

提交讀演示

客戶端A 開啓事務,並更新數據

 此時事務尚未提交,開啓客戶端B,並進行查詢,此時的數據仍是未更新前的

 客戶端A進行事務提交,而後客戶端B查詢,此時是最新的數據

 

 commit and chain的演示

若是在提交的時候使用commit and chain,那麼在提交後當即開始一個新的事務

 A提交事務後,B再進行查詢

 開啓事務會隱式解鎖

鎖表期間,用start transaction 命令開始一個新事務,則會隱式的執行unlock tables

A對錶進行寫鎖操做

此時B進行查詢:因爲被A鎖表,因此查詢被阻塞

A開啓一個事務

因爲A開啓事務,隱式的釋放了寫鎖,因此B的查詢再也不被阻塞

 

 SAVEPOINT的使用

事務中能夠經過定義SAVEPOINT,指定回滾事務的一個部分
A開啓事務並insert一條記錄,並設置savepoint

 B進行查詢,查詢到的是開啓事務前的數據

 A又插入一條數據,而後回滾到savepoint

 

 B進行查詢

 

相關文章
相關標籤/搜索