面試官問你:MySQL事務和隔離級別,該如何回答

clipboard.png

1、事務

事務是由一組SQL語句組成的邏輯處理單元,是知足 ACID 特性的一組操做,能夠經過 Commit 提交一個事務,也可使用 Rollback 進行回滾。事務具備如下4個屬性,一般簡稱爲事務的ACID屬性:java

  • 原子性(Atomicity):事務是一個原子操做單元,其對數據的修改,要麼全都執行,要麼全都不執行。好比在同一個事務中的SQL語句,要麼所有執行成功,要麼所有執行失敗。回滾能夠用日誌來實現,日誌記錄着事務所執行的修改操做,在回滾時反向執行這些修改操做便可。
  • 一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。這意味着全部相關的數據規則都必須應用於事務的修改,以保持數據的完整性;事務結束時,全部的內部數據結構(如B樹索引或雙向鏈表)也都必須是正確的。 以轉帳爲例子,A向B轉帳,假設轉帳以前這兩個用戶的錢加起來總共是2000,那麼A向B轉帳以後,無論這兩個帳戶怎麼轉,A用戶的錢和B用戶的錢加起來的總額仍是2000,這個就是事務的一致性。
  • 隔離性(Isolation):數據庫系統提供必定的隔離機制,保證事務在不受外部併發操做影響的「獨立」環境執行。 隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離。即要達到這麼一種效果:對於任意兩個併發的事務 T1 和 T2,在事務 T1 看來,T2 要麼在 T1 開始以前就已經結束,要麼在 T1 結束以後纔開始,這樣每一個事務都感受不到有其餘事務在併發地執行。
  • 持久性(Durable):事務完成以後,它對於數據的修改是永久性的,即便出現系統故障也可以保持。  能夠經過數據庫備份和恢復來實現,在系統發生奔潰時,使用備份的數據庫進行數據恢復。
MySQL 默認採用 自動提交模式。也就是說,若是不顯式使用 START TRANSACTION 語句來開始一個事務,那麼每一個查詢都會被當作一個事務自動提交。

clipboard.png

這幾個特性不是一種平級關係程序員

  • 只有知足一致性,事務的執行結果纔是正確的。
  • 在無併發的狀況下,事務串行執行,隔離性必定可以知足。此時要只要能知足原子性,就必定能知足一致性。
  • 在併發的狀況下,多個事務併發執行,事務不只要知足原子性,還須要知足隔離性,才能知足一致性。
  • 事務知足持久化是爲了能應對數據庫奔潰的狀況。

2、併發一致性問題

Ⅰ、更新丟失(Lost Update)

T1 和 T2 兩個事務都對一個數據進行修改,T1 先修改,T2 隨後修改,T2 的修改覆蓋了 T1 的修改數據庫

例如,兩個程序員修改同一java文件。每程序員獨立地更改其副本,而後保存更改後的副本,這樣就覆蓋了原始文檔。最後保存其更改副本的編輯人員覆蓋前一個程序員所作的更改。數據結構

若是在一個程序員完成並提交事務以前,另外一個程序員不能訪問同一文件,則可避免此問題併發

clipboard.png

Ⅱ、髒讀

一句話:事務B讀取到了事務A已修改但還沒有提交的的數據,還在這個數據基礎上作了操做。此時,若是A事務回滾Rollback,B讀取的數據無效,不符合一致性要求。性能

解決辦法: 把數據庫的事務隔離級別調整到 READ_COMMITTED學習

T1 修改一個數據,T2 隨後讀取這個數據。若是 T1 撤銷了此次修改,那麼 T2 讀取的數據是髒數據spa

clipboard.png

Ⅲ、不可重複讀(Non-Repeatable Reads)

在一個事務內,屢次讀同一個數據。在這個事務尚未結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務的兩次讀數據之間。因爲第二個事務的修改,那麼第一個事務讀到的數據可能不同,這樣就發生了在一個事務內兩次讀到的數據是不同的,所以稱爲不可重複讀,即原始讀取不可重複。3d

一句話:一個事務範圍內兩個相同的查詢卻返回了不一樣數據日誌

同時操做,事務1分別讀取事務2操做時和提交後的數據,讀取的記錄內容不一致。不可重複讀是指在同一個事務內,兩個相同的查詢返回了不一樣的結果

解決辦法: 若是隻有在修改事務徹底提交以後才能夠讀取數據,則能夠避免該問題。把數據庫的事務隔離級別調整到REPEATABLE_READ

T2 讀取一個數據,T1 對該數據作了修改。若是 T2 再次讀取這個數據,此時讀取的結果和第一次讀取的結果不一樣

clipboard.png

Ⅳ、幻讀

一個事務T1按相同的查詢條件從新讀取之前檢索過的數據,卻發現其餘事務T2插入了知足其查詢條件的新數據,這種現象就稱爲「幻讀」。(和可重複讀相似,可是事務 T2 的數據操做僅僅是插入和刪除,不是修改數據,讀取的記錄數量先後不一致)

一句話:事務A 讀取到了事務B提交的新增數據,不符合隔離性。

解決辦法: 若是在操做事務完成數據處理以前,任何其餘事務都不能夠添加新數據,則可避免該問題。把數據庫的事務隔離級別調整到 SERIALIZABLE_READ。

T1 讀取某個範圍的數據,T2 在這個範圍內插入新的數據,T1 再次讀取這個範圍的數據,此時讀取的結果和和第一次讀取的結果不一樣

clipboard.png

3、事務隔離級別

"髒讀"、"不可重複讀"和"幻讀",其實都是數據庫讀一致性問題,必須由數據庫提供必定的事務隔離機制來解決

數據庫的事務隔離越嚴格,併發反作用越小,但付出的代價也就越大,由於事務隔離實質上就是使事務在必定程度上 「串行化」進行,這顯然與「併發」是矛盾的。同時,不一樣的應用對讀一致性和事務隔離程度的要求也是不一樣的,好比許多應用對「不可重複讀」和「幻讀」並不敏感,可能更關心數據併發訪問的能力。

MYSQL常看當前數據庫的事務隔離級別:show variables like 'tx_isolation';

Ⅰ、讀未提交 (Read Uncommitted)

最低的隔離等級,容許其餘事務看到沒有提交的數據,會致使髒讀。

Ⅱ、讀已提交 (Read Committed)

被讀取的數據能夠被其餘事務修改,這樣可能致使不可重複讀。也就是說,事務讀取的時候獲取讀鎖,可是在讀完以後當即釋放(不須要等事務結束),而寫鎖則是事務提交以後才釋放,釋放讀鎖以後,就可能被其餘事務修改數據。該等級也是 SQL Server 默認的隔離等級。

Ⅲ、可重複讀(Repeatable Read)

全部被 Select 獲取的數據都不能被修改,這樣就能夠避免一個事務先後讀取數據不一致的狀況。可是卻沒有辦法控制幻讀,由於這個時候其餘事務不能更改所選的數據,可是能夠增長數據,即前一個事務有讀鎖可是沒有範圍鎖,爲何叫作可重複讀等級呢?那是由於該等級解決了下面的不可重複讀問題。(引伸:如今主流數據庫都使用 MVCC 併發控制,使用以後RR(可重複讀)隔離級別下是不會出現幻讀的現象。)

MYSQL默認是REPEATABLE-READ

Ⅳ、串行化(Serializable)

全部事務一個接着一個的執行,這樣能夠避免幻讀 (phantom read),對於基於鎖來實現併發控制的數據庫來講,串行化要求在執行範圍查詢的時候,須要獲取範圍鎖,若是不是基於鎖實現併發控制的數據庫,則檢查到有違反串行操做的事務時,需回滾該事務。

Ⅴ、總結

  • 讀未提交: 一個事務還沒提交時,它作的變動就能被別的事務看到
  • 讀提交: 一個事務提交以後,它作的變動纔會被其餘事務看到。
  • 可重複讀 : 一個事務執行過程當中看到的數據,老是跟這個事務在啓動時看到的數據是一致的。固然在可重複讀隔離級別下,未提交變動對其餘事務也是不可見的。
  • 串行化: 顧名思義是對於同一行記錄,「寫」會加「寫鎖」,「讀」會加「讀鎖」。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。

四個級別逐漸加強,每一個級別解決一個問題,事務級別越高,性能越差,大多數環境(Read committed 就能夠用了)

隔離級別 讀數據一致性 髒讀 不可重複讀 幻影讀
未提交讀 最低級別
提交讀 語句級 ×
可重複讀 事務級 × ×
可串行讀 最高級別,事務級 × × ×

寫在最後

  • 第一:看完點贊,感謝您對做者的承認;
  • ...
  • 第二:隨手轉發,分享知識,讓更多人學習到;
  • ...
  • 第三:記得點關注,天天更新的!!!
  • ...
相關文章
相關標籤/搜索