mysql總結(二)-事務

事務隔離級別

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

//session B 
begin;
select * from t1 where id = 1
update t1 set amonut=amount+1 where id = 1

//session A 
select * from t1 where id = 1 //v1

// session B 
commit 

// session A 
select * from t1 where id = 1 //v2
commit 
select * from t1 where id = 1 //v3

複製代碼

上面的查詢分析來分析每一個事務隔離級別下v1,v2,v3不一樣的顯示mysql

  1. 若隔離級別是「讀未提交」, 則 V1 的值就是 2。這時候事務 B 雖然尚未提交,可是結果已經被 A 看到了。所以,V二、V3 也都是 2
  2. 若隔離級別是「讀提交」,則 V1 是 1,V2 的值是 2。事務 B 的更新在提交後才能被 A 看到。因此, V3 的值也是 2。
  3. 若隔離級別是「可重複讀」,則 V一、V2 是 1,V3 是 2。之因此 V2 仍是 1,遵循的就是這個要求:事務在執行期間看到的數據先後必須是一致的。
  4. 若隔離級別是「串行化」,則在事務 B 執行「將 1 改爲 2」的時候,會被鎖住。直到事務 A 提交後,事務 B 才能夠繼續執行。因此從 A 的角度看, V一、V2 值是 1,V3 的值是 2。

事務隔離的實現

MySQL 中,實際上每條記錄在更新的時候都會同時記錄一條回滾操做。記錄上的最新值,經過回滾操做,均可以獲得前一個狀態的值sql

假設一個值從1被按順序的改成2,3,4,在回滾日誌裏面就會有下面的記錄數據庫

read-view A -> 將2改成1 
read-view B -> 將3改成2 將4改成3 
read-view C -> 當前值4 
複製代碼

經過不一樣時刻啓動不一樣的read-view,在視圖A,B,C裏面,這個記錄的值分別爲1,2,4,同一記錄存在多個版本,就是數據庫的多版本(MVCC).對於 read-view A,要獲得 1,就必須將當前值依次執行圖中全部的回滾操做獲得.同時你會發現,即便如今有另一個事務正在將 4 改爲 5,這個事務跟 read-view A、B、C 對應的事務是不會衝突的session

事務日誌的刪除和長事務

在不須要的時候才刪除。也就是說,系統會判斷,當沒有事務再須要用到這些回滾日誌時,回滾日誌會被刪除,當系統裏沒有比這個回滾日誌更早的 read-view 的時候就會刪除.spa

長事務意味着系統裏面會存在很老的事務視圖。因爲這些事務隨時可能訪問數據庫裏面的任何數據,因此這個事務提交以前,數據庫裏面它可能用到的回滾記錄都必須保留,這就會致使大量佔用存儲空間.==長事務還佔用鎖資源,也可能拖垮整個庫==日誌

事務MVCC的簡單分析

  1. 每一個事務都有一個事務ID,叫作transaction id(遞增)code

  2. 事務在啓動時,找到已提交的最大事務ID記爲up_limit_id。事務

  3. 事務在更新一條語句時,好比id=1改成了id=2.會把id=1和該行以前的row trx_id寫到undo log裏,而且在數據頁上把id的值改成2,而且把修改這條語句的transactionid記在該行行頭資源

  4. 一個事務要查看一條數據時,必須先用該事務的up_limit_id與該行的transaction id作比對,若是up_limit_id>=transactionid,那麼能夠看.若是up_limit_id<transaction id,則只能去undo log裏去取。去undo log查找數據的時候,也須要作比對,必須up_limit_id>transaction id,才返回數據it

事務的可見性

// session A 
start transaction with consistent snapshot   //立刻啓動事務

// session B 
start transaction with consistent snapshot

// session C 
UPDATE t set k=k+1 where id =1 

// session B 
UPDATE t set k=k+1 where id =1 
SELECT k from t where id = 1  //查詢結果 3 

// session A 
SELECT k from t where id = 1 //查詢結果 1 
commit 

// session B 
comit 


複製代碼
  1. A的查詢語句是1 由於他的查詢是在B視圖查詢以後,可重複讀的特性是在其餘事務的更改對當前事務部可見
  2. B的查詢語句是3 所以B的查詢語句是在C的提交以後,在當前事務進行的更改,未提交對當前事務也是可見的,B的查詢是3是由於更新的時候須要去讀一次,而C已經進行語句提交了,所以B的更新語句先在當前事務查詢到k的值爲2,再進行更新一次爲3.所以==更新數據都是先讀後寫的,而這個讀,只能讀當前的值,稱爲「當前讀」(current read)==

一個數據版本,對於一個事務視圖來講,除了本身的更新老是可見之外,有三種狀況

  1. 版本未提交,不可見;
  2. 版本已提交,可是是在視圖建立後提交的,不可見;
  3. 版本已提交,並且是在視圖建立前提交的,可見。

事務和鎖

上面的例子 咱們將事務C也進行聲明事務,接下來看看會怎麼樣

// session A 
start transaction with consistent snapshot   //立刻啓動事務

// session B 
start transaction with consistent snapshot

// session C 
start transaction with consistent snapshot // C也啓動事務
UPDATE t set k=k+1 where id =1 

// session B 
UPDATE t set k=k+1 where id =1 
SELECT k from t where id = 1  //查詢結果 3 

// session C
commit 

// session A 
SELECT k from t where id = 1 //查詢結果 1 
commit 

// session B 
comit 

複製代碼

相對於上個版原本說,事務B的更新的時候,事務C還未進行提交,這樣的話當前A,B的查詢結果會是什麼樣子呢?

上一篇文章中提到的「兩階段鎖協議」就要上場了。事務 C’沒提交,也就是說 (1,2) 這個版本上的寫鎖還沒釋放。而事務 B 是當前讀,必需要讀最新版本,並且必須加鎖,所以就被鎖住了,==必須等到事務 C’釋放這個鎖==,才能繼續它的當前讀

可重複讀的核心就是==一致性讀==;而事務更新數據的時候,只能用當前讀。若是當前的記錄的行鎖被其餘事務佔用的話,就須要進入鎖等待。而讀提交的邏輯和可重複讀的邏輯相似,它們最主要的區別是:

  1. 在可重複讀隔離級別下,只須要在事務開始的時候建立一致性視圖,以後事務裏的其餘查詢都共用這個一致性視圖;
  2. 在讀提交隔離級別下,每個語句執行前都會從新算出一個新的視圖。
相關文章
相關標籤/搜索