事務隔離髒讀幻讀 mysql

2021-10-09 03:45:14 字數 2670 閱讀 4838

先說什麼叫做「事務隔離」,事務隔離是指多個事務同時在進行中(如果只有乙個事務,那就無所謂隔離不隔離了)時,各個事務被隔離開來,相互之間的影響和事物的隔離級別有關,按照「讀未提交」–>「讀已提交」–>「可重複讀」–>「序列化」的順序,越往後面隔離級別越高,事務之間的影響越小。

下面的內容都以這個資料表為例進行說明:

idmoney110

220440

兩個同時進行的事務a、b,a會讀到b還未提交的的資料,這種事務隔離級別會存在髒讀的問題,舉個例子:

b修改id=2的money為200,但是尚未提交,然後a讀取id為2的money,這是讀到的值是200,然後b因為某種原因(比如系統異常)導致事務回滾了,此時2最終的money仍然是20。說明a讀到了髒資料。

a                        b

begin

update table set money = 200 where id = 2

select money from table where id = 2

rollback

為了解決髒讀的問題,可以將事務隔離級別調整到「讀已提交」,這種隔離級別下,事務a只能讀到事務b提交後的資料,但是這種隔離級別雖然解決了髒讀的問題,但是無法解決可重複讀的問題,即在事務a中,兩次執行相同的讀取語句,讀到的內容卻是不一樣的。舉例如下

a                        b

begin                       begin

update table set money = 200 where id = 2

select money from table where id = 2

commit

select money from table where id = 2

commit

事務a中第一次select時,讀到的值是20,第二次再執行select時,讀取到的值是200。這就是不可重複讀。

為了解決不可重複讀的問題,可以將事務隔離級別調整到「可重複讀」,這種隔離級別下,可以保證在同乙個事務中只會讀取到當前事務對資料的修改,其他事務修改的資料不會影響到當前事務的任何一次讀取。還是上面的例子,事務a兩次select讀取到的結果都是20,即可重複讀.

可重複讀雖然解決了不可重複讀的問題,但是仍然存在幻讀的問題。

對於幻讀的解釋,大多數部落格中都是有問題的,甚至《高效能mysql》中,也沒有詳細解釋幻讀的問題

我們先來看看網上出現最多的幻讀的解釋,務必注意,這種解釋是錯誤的:

a                        b

begin                      begin

select money from table where id > 2

inser into table values(3,30)

commit

select money from table where id > 2

commit

網上多數觀點認為,當a進行範圍查詢時,b在其中插入一條資料,a再次執行該範圍查詢是,就會比第一次查詢時多出來b剛才插入的那條資料,像幻影一樣,所以出現了幻讀。

為什麼這種說法是不對的呢?

從實踐上看,直接去msql中試試就會發現,其實a連個執行的查詢結果仍然是一樣的,並不會出現幻讀的現象。

從原理上看,可重複讀是靠mvcc(多版本併發控制)保證的,該模式下,保證事務只能讀取到當前事務開啟之前已經提交的事務進行的修改以及當前事務本身對資料的修改。按照這個定義,上述實驗中的b事務並不會影響到a的讀取。

那麼什麼事真正的幻讀呢?來看下面的例子

a                        b

begin                      begin

select money from table where id > 2

inser into table values(3,30)

commit

update table set money = 0 where id > 2

select money from table where id > 2

commit

在b事務提交之後,a事務第二次select之前,先進行一次update操作,然後a再次執行select時,id=3的行就會出現,而且money的值是0.出現了幻讀。

mvcc只對讀有效,對寫操作無效,由於update是寫操作,所以為更新b已經插入的id=3的行,將money更新成0,此時id=3的行被a事務(當前事務)修改了,所以a事務中第二次select時,是可以看到被當前事務修改(update)的資料的,所以id=3的行會出現在select的結果中,這就是幻讀出現的原因。

序列將所有的事務乙個接乙個的進行,不存在多個事務同事進行的情況,所以序列的事務隔離級別不會出現上面提到的髒讀、不可重複讀、幻讀等任何一種問題。代價是,嚴重影響了資料庫的效能。

事務隔離級別需要根據具體的業務場景來選擇,並沒有哪乙個級別是萬能的。

有些場景下,甚至根本不需要事務,這時候,也許myisam引擎才是最合適的。

oracle的預設事務隔離級別是讀已提交,而mysql的預設事務隔離級別是可重複讀,根據也無需要,可以把mysql的隔離級別調整到「度已提交」。

「讀未提交」和「序列」這兩種隔離級別因為髒讀和效能的問題,業內用的很少。

事務 隔離級別 髒讀 不可重複 幻讀

事務,就是一組運算元據庫的動作集合。如果一組 處理步驟 全部發生或者一步也不執行,我們稱該組處理步驟為乙個事務。當所有的步驟像乙個操作一樣被完整地執行,我們稱該事務被提交。由於其中的一部分或多步執行失敗,導致沒有步驟被提交,則事務必須回滾到最初的系統狀態。二 事務的併發問題 1 髒讀 事務 a讀取了...

MySQL事務隔離級別以及髒讀 幻讀 不可重複讀

事務的隔離性 mysql是乙個客戶端 伺服器架構的軟體,對於同乙個伺服器來說,可以有若干個客戶端與之連線,每個客戶端與伺服器連線上之後,就可以稱之為乙個會話 session 每個客戶端都可以在自己的會話中向伺服器發出請求語句,乙個請求語句可能是某個事務的一部分,也就是對於伺服器來說可能同時處理多個事...

Mysql事務 髒讀,可重複讀,幻讀 測試

1 開啟mysql的命令列,將自動提交事務給關閉 檢視是否是自動提交 1表示開啟,0表示關閉 select autocommit 設定關閉 set autocommit 0 2 資料準備 建立資料庫 create database tran 切換資料庫 兩個視窗都執行 use tran 準備資料 c...