Mysql 事務隔離級別

作者:杯叔書

原文:https://www.jianshu.com/p/29b33f210c0f

爲什麼需要事務隔離

數據庫不會只服務於一個客戶端,肯定會出現多個請求同時落到數據庫上,即使是同一個客戶端也會併發執行多個事務。併發操作 mysql 的同一批數據的時候就有可能出現數據安全問題,主要有:髒寫、髒讀、不可重複讀、幻讀這些問題。本質上這些問題就是多事務併發的問題,那事務隔離就是爲了解決這些問題而設計的。

認識多事務併發問題

先了解多事務併發會帶來什麼問題,問題是什麼樣子的後面纔好解決。主要有以下幾個問題:更新丟失 (Lost Update) 或髒寫
當個事務操作同一行,然後基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題。最後的更新覆蓋了由其他事務所做的更新

如上圖兩個事務都更新 id=1,最終持久化的數據只有一個事務的值。假設 B 事務晚提交,那對 A 事務來說就莫名其妙,它更新的 50 去哪裏了?

髒讀(Dirty Reads)
一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的數據就處於不一致的狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些 “髒” 數據,並據此作進一步的處理,就會產生未提交的數據依賴關係。這種現象被形象地叫做“髒讀”。簡單點說就是事務 A 讀取到了事務 B 已經修改但尚未提交的數據。

A 事務先更新 a=50,B 事務讀到 a=50 並做業務處理,但是在往下的時候 A 事務回滾了,但是 B 事務的業務卻執行成功了。對 B 事務來說這就是髒讀。

不可重讀(Non-Repeatable Reads) 

一個事務在讀取某些數據後的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象就叫做 “不可重複讀”。簡單的說就是事務 A 內部的相同查詢語句在不同時刻讀出的結果不一致。

上圖所示 A 事務裏面每一次查詢 id=1 的時候 a 的值都在變化,這讓 A 事務怎麼去處理業務,根本沒辦法處理,對 A 事務來說這個 a 的值就是不可重複讀。

幻讀(Phantom Reads)

一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱爲 “幻讀”。簡單地說就是事務 A 讀取到了事務 B 提交的新增數據。
幻讀跟不可重複讀有點像,不可重複讀是讀到數據不一樣,幻讀是讀的數據多了。

A 事務第一次查 id<10 的時候只有兩條記錄,B 事務新增一條,A 事務在查的時候卻有三條記錄,這對 A 事務來說就是幻讀。
好,以上就是多併發事務帶來的幾個問題,下面看下事務隔離機制是怎麼解決的。

認識事務

瞭解事務隔離機制之前,先了解下什麼是事務。事務是由一組 SQL 語句組成的邏輯處理單元, 事務具有以下 4 個屬性, 通常簡稱爲事務的 ACID 屬性。
原子性 (Atomicity) :事務內的所有操作是一個原子操作, 其對數據的修改, 要麼全都執行, 要麼全都不執行。主要體現在操作上全部執行或全部不執行。
一致性 (Consistent) :在事務開始和完成時, 數據都必須保持一致狀態。這意味着所有相關的數據規則都必須應用於事務的修改, 以保持數據的完整性。主要體現在數據上全部已改成功或沒改變。
隔離性 (Isolation) :數據庫系統提供一定的隔離機制, 讓事務內的所有操作是獨立的事務之間互不影響
持久性 (Durable) :事務完成之後, 它對於數據的修改是永久的, 即使出現系統故障也能夠保持。

認識事務隔離級別

mysql 的事務隔離機制是有四個等級的分別是

  1. 讀未提交,也就是說另一個事務未提交的操作就能讀到,這樣顯然會造成髒讀,因爲未提交的數據有可能失敗,還會造成不可重複讀和幻讀就更好理解了。未提交的數據都能讀到,那其他不管有提交沒提交的數據都能被當前事物讀到造成數據每次讀到都不一樣。
  2. 讀已提交,也就是已提交成功的數據才能讀到,那髒讀是不可能發生的,因爲已提交的數據說明是成功的數據,讀到的自然不是髒數據。但是依然會造成不可重複讀和幻讀,其他事物成功修改或新增都被當前事物讀到,對當前事物來說就是不可重複讀和幻讀。
  3. 可重複讀,解決了髒讀和不可重複讀的問題,但是幻讀的可能性還是會存在。比如其他事務插入一條記錄 ID=100 的記錄,當前事務查詢的時候 where id <=100 是不會查到這個記錄的,但是當前事務 update shere id=100 的時候還是能修改的,所以本質上能感知到新增的數據,所以幻讀還是會存在。
  4. 可串行化,解決了髒讀、不可重複讀和幻讀但是代價也是很大的。因爲他是用加鎖同步的方式實現只能一個事物一個事務的執行,這顯然不能滿足日常性能要求。

mysql 默認的事務隔離級別是可重複讀,可以用 show variables like 'tx_isolation'; 查看當前事務的隔離級別。也可以用 set tx_isolation='REPEATABLE-READ'; 來設置當前事務的隔離級別。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/SLgcBvGPBqN_TxjHQoWjeA