1. 程式人生 > >談談MySQL的事務隔離級別

談談MySQL的事務隔離級別

提交 執行過程 操作 dnf 情況 以及 讀取 int 並且

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

一、事務

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

  作為單個邏輯單元執行一系列操作,要麽完全執行,要麽完全不執行。事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。

事務有四個屬性,稱為ACID屬性:

1、原子性(Atomicity):事務是一個原子單位,要麽全部執行,要麽全部不執行。

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

3、隔離性(isolation):數據庫系統提供隔離機制,保證並發事務之間是互相不幹擾的。也就意味著事務處理過程中的中間狀態對其他的事務是透明的。

4、持久性(Durable):事務完成之後,對數據的修改是永久性的,即使出現系統故障也能夠保持。

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

這個很簡單,如果沒有事務,我們平時生活中的銀行轉賬就無法操作。

二、數據庫讀現象

  ACID屬性裏面有一個是隔離級別,即並發事務之間互相不幹擾。互相不幹擾只是一個終極狀態,且需要消耗巨大的性能。在我們實際應用過程中,是存在很大的灰度空間的:隔離級別有程度的區分。所以如果隔離程度控制的比較弱的話,就會產生臟讀不可重復讀以及幻讀的現象。

1、臟讀

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

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

2、不可重復讀

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

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

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

3、幻讀

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

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

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

如果需要解決臟讀、不可重復讀、幻讀等這些數據庫讀現象,就必須相應提高事務的隔離級別。但是數據庫的隔離級別越高,對應的並發能力就越弱,性能也就相應的越差,所以我們還需根據具體的應用場景去權衡。

三、事務隔離級別

1、未提交讀

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

數據庫鎖實現原理:

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

T1在讀取數據時,T2可以對相同數據進行讀取、修改。因為T1沒有進行任何鎖操作;當T2對記錄進行修改時,T1再次讀取數據可以讀取到T2修改後的數據。因為T2對數據進行修改只增加了行級共享鎖,T1可以再增加共享讀鎖進行數據讀取(盡管T2沒有提交事務)

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

2、已提交讀

在一個事務修改數據過程中,如果事務沒有進行提交,其他事務不能讀取該數據

數據庫鎖實現原理:

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

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

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

3、可重復讀

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

數據庫鎖實現原理:

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

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

T1進行查詢,讀取了10條記錄,並對十條記錄增加了行級鎖,此時T2是無法對這10行數據進行修改操作的,但是由於沒有表級鎖,它可以增加一條滿足T1查詢條件的記錄。隨後T1在進行查詢時,會發現雖然10條記錄沒有改變,但是突然多了一條記錄。

4、序列化

產生幻讀是由於沒有進行範圍查詢時沒有增加範圍鎖。

數據庫鎖實現原理:

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

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

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

四、事務操作實踐

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

如果我們想要同時執行多條SQL,並且執行過程中有SQL執行異常,需要回滾前面已經成功執行的SQL或者最終想回滾全部,則必須顯示的使用事務。

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

  2. 提交事務:commit;

  3. 回滾事務:rollback;

  4. 事務提交之後的操作:chain;

  5. 事務回滾之後的操作:release;

  6. 修改當前連接的提交方式: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進行查詢

技術分享圖片

作者:冬瓜蔡
原文:http://www.cnblogs.com/dongguacai/p/7114885.html

更多Mysql參考內容:http://www.roncoo.com/article/index?tn=Mysql

談談MySQL的事務隔離級別