MySQL事務隔離級別

在MySQL中,實現了這四種隔離級別,分別有可能產生問題以下所示:數據庫

首先建立一個表account。建立表的過程略過(因爲InnoDB存儲引擎支持事務,因此將表的存儲引擎設置爲InnoDB)。表的結構以下:session

表結構性能

而後往表中插入兩條數據,插入後結果以下:spa

數據code

爲了說明問題,咱們打開兩個控制檯分別進行登陸來模擬兩個用戶(暫且成爲用戶A和用戶B吧),並設置當前MySQL會話的事務隔離級別。blog

一. read uncommitted(讀取未提交數據)

具體用戶A的操做以下:事務

set session transaction isolation level read uncommitted;
start transaction;
select * from account;

結果以下:it

 

數據io

用戶B的操做以下:table

set session transaction isolation level read uncommitted;
start transaction;
update account set account=account+200 where id = 1;

隨後咱們在A用戶中查詢數據,結果以下:

 

uncommittedA數據

結論一:

咱們將事務隔離級別設置爲read uncommitted,即使是事務沒有commit,可是咱們仍然能讀到未提交的數據,這是全部隔離級別中最低的一種。

那麼這麼作有什麼問題嗎?

那就是咱們在一個事務中能夠隨隨便便讀取到其餘事務未提交的數據,這仍是比較麻煩的,咱們叫髒讀。我不知道這個名字是怎麼起的,爲了加強你們的印象,能夠這麼想,這個事務好輕浮啊,飢渴到連別人沒提交的東西都等不及,真髒,呸!

實際上咱們的數據改變了嗎?

答案是否認的,由於只有事務commit後纔會更新到數據庫。

二. read committed(能夠讀取其餘事務提交的數據)---大多數數據庫默認的隔離級別

一樣的辦法,咱們將用戶B所在的會話當前事務隔離級別設置爲read commited。

在用戶A所在的會話中咱們執行下面操做:

update account set account=account-200 where id=1;

 

read committed

咱們將id=1的用戶account減200。而後查詢,發現id=1的用戶account變爲800。

在B用戶所在的會話中查詢:

select * from account;

結果以下:

 

read committedB

咱們會發現數據並無變,仍是1000。

接着在會話A中咱們將事務提交:

commit;

在會話B中查詢結果以下:

 

read committedB1

結論二:

當咱們將當前會話的隔離級別設置爲read committed的時候,當前會話只能讀取到其餘事務提交的數據,未提交的數據讀不到。

那麼這麼作有什麼問題嗎?

那就是咱們在會話B同一個事務中,讀取到兩次不一樣的結果。這就形成了不可重複讀,就是兩次讀取的結果不一樣。這種現象叫不可重複讀

三. repeatable read(可重讀)---MySQL默認的隔離級別

如今有個需求,就是老闆說在同一個事務中查詢結果必須保持一致,若是你是數據庫,你會怎麼作?數據庫是這麼作的。

在會話B中咱們當前事務隔離級別爲repeatable read。具體操做以下:

set session transaction isolation level repeatable read;
start transaction;

接着在會話B中查詢數據:

 

repeatablereadB1

咱們在A用戶所在會話中爲表account添加一條數據:

insert into account(id,account) value(3,1000);
commit;

而後咱們查詢看數據插入是否成功:

 

repeatable readA

回到B用戶所在的會話,咱們查詢結果:

 

repeatablereadB2

用戶B在他所在的會話中想插入一條新數據id=3,value=1000。來咱們操做下:

 

readpeatablereadB3

什麼?居然插不進去,說我數據重複?

用戶B固然不服啊,由於查詢到數據只有兩條啊,爲何插入id=3說我數據重複了呢?

我再看一遍,莫非我眼花了?

 

repeatablereadB2

試想一下,在實際中用戶A和用戶B確定是相互隔離的,彼此不知道操做什麼。用戶B碰到這種現象,確定會炸毛的啊,明明不存在的數據,插入卻說主鍵id=3數據重複了。

結論三:

當咱們將當前會話的隔離級別設置爲repeatable read的時候,當前會話能夠重複讀,就是每次讀取的結果集都相同,而無論其餘事務有沒有提交。

有什麼問題嗎?

管他呢,老闆的要求知足了。要一個事務中讀取的數據一致(可重複讀)。我只能這麼作啊,打腫臉裝胖子。數據已經發生改變,可是我仍是要保持一致。可是,出現了用戶B面對的問題,這種現象叫幻讀(記得當時就在這個地方糾結很久,到底什麼是幻讀啊)。

四. serializable(串行化)

一樣,咱們將用戶B所在的會話的事務隔離級別設置爲serializable並開啓事務。

set session transaction isolation level serializable;
start transaction;

在用戶B所在的會話中咱們執行下面操做:

select * from account;

結果以下:

 

serializableA

那咱們這個時候在用戶A所在的會話中寫數據呢?

 

 

readcommittedA1

咱們發現用戶A所在的會話陷入等待,若是超時(這個時間能夠進行配置),會出現Lock wait time out提示:

 

readcommittedA2

若是在等待期間咱們用戶B所在的會話事務提交,那麼用戶A所在的事務的寫操做將提示操做成功。

結論四:

當咱們將當前會話的隔離級別設置爲serializable的時候,其餘會話對該表的寫操做將被掛起。能夠看到,這是隔離級別中最嚴格的,可是這樣作勢必對性能形成影響。因此在實際的選用上,咱們要根據當前具體的狀況選用合適的。

相關文章
相關標籤/搜索