mysql的事務隔離級別

事務的四大特性(ACID):

1.原子性(atomicity):一個事務必須視爲一個不可分割的最小工作單元,整個事務中的所有操作要麼全部提交成功,要麼全部失敗回滾,對於一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性。

2.一致性(consistency):數據庫總數從一個一致性的狀態轉換到另一個一致性的狀態,比如無論a給b怎麼轉賬或b轉a,兩個人最後的金額加起來==沒轉賬前的總金額。

3.隔離性(isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。

4.持久性(durability):一旦事務提交,則其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,修改的數據也不會丟失,因爲數據已經保存在硬盤中了。

mysql事務隔離級別有4個級別:

數據庫事務的隔離級別有4種,由低到高分別爲Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事務的併發操作中可能會出現髒讀,不可重複讀,幻讀。下面通過事例一一闡述它們的概念與聯繫。

1.Read uncommitted

讀未提交,顧名思義,就是一個事務可以讀取另一個未提交事務的數據。

----------------------------------------------------------------------------------------------------------------------------

mysql數據庫表準備工作,創建表並初始化數據:

create table account(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `balance` int NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`)
);

insert into account values(1,1000);
insert into account values(2,1000);

insert into account values(3,1000);
insert into account values(4,1000);

----------------------------------------------------------------------------------------------------------------------------

例子:

set session transaction isolation level Repeatable read;// 設置mysql的事務隔離級別爲Read uncommitted

select @@transaction_isolation;// 查看當前事務隔離級別(檢查是否設置成功)

set @@autocommit=0; // 把mysql的自動提交設置爲false

start transaction;// 開啓一個事務

注:這裏打開兩個終端來測試,分別代表一個事務,左右各一個。

把上面的語句按順序在兩個終端各執行一遍後可以看到兩個事務的隔離級別都是讀未提交。

1.分別在兩個事務中查看錶的數據,如圖:

2.在右邊終端執行update account a set a.balance=a.balance - 200 where a.id=1,再次查看兩個終端的表數據,如圖:

這就是髒讀,讀未提交隔離級別什麼都防止不了。此時如果右終端回滾事務,那麼之前update也就相當於沒執行,而左終端讀取了update後的數據去進行了一些業務操作,那麼後果將是很嚴重的。因爲讀取數據是不準確的。

舉個栗子:

老闆要給程序員發工資,程序員的工資是3.6萬/月。但是發工資時老闆不小心按錯了數字,按成3.9萬/月,但是事務還沒有提交,就在這時,程序員去查看自己這個月的工資,發現比往常多了3千元,以爲漲工資了非常高興。但是老闆及時發現了不對,馬上回滾差點就提交了的事務,將數字改成3.6萬再提交。

分析:實際程序員這個月的工資還是3.6萬,但是程序員看到的是3.9萬。他看到的是老闆還沒提交事務時的數據。這就是髒讀。
----------------------------------------------------------------------------------------------------------------------------

如何解決髒讀的發生?----->Read committed 讀已提交

讀提交,顧名思義,就是一個事務要等另一個事務提交後才能讀取它的數據,否則是讀取不到另外一個事務的更改的。

1.將數據庫中的事務隔離級別修改爲Read committed,並左右終端都開啓事務(可參考上面的語句),查詢表數據,效果如圖:

2.在右邊終端執行update account a set a.balance=a.balance - 200 where a.id=1,再次查看兩個終端的表數據,如圖:

雖然讀已提交解決了髒讀的問題,又發生了問題:

比如左終端事務id爲1的用戶去超市消費了800,在刷卡結賬的時候查詢卡里有1000元,就在這時,右終端事務也就是用戶的女朋友,把卡里的錢全部轉到了她自己的支付寶上,並提交了事務,然後用戶輸入密碼扣款,收銀員告訴用戶說卡里沒有錢了(這是用戶腦子在想:“剛剛刷的時候我還看到有1000的啊,怎麼突然就沒了”,這個時候用戶的電話響了,打給他的是他女朋友跟他說“我要用錢買點東西就把你卡里的錢提到我支付寶上了”)這時候用戶才緩過神來,不然以爲見鬼了呢!

用實際行動來證明上面的問題是存在的:

(用戶女朋友)假設右終端是用戶的女朋友,把錢提到支付賬號金額爲200(執行的語句就是第二步的sql),並提交執行commit

(用戶自己)執行扣款,扣款金額是900,執行sql:update account set balance = balance-900 where id =1

假設超市的扣款系統會再次去查詢用戶的金額,判斷是否足夠再進行扣款那麼就將導致扣款失敗,因爲被女朋友取走200只剩800了。如果沒有二次查詢用戶的金額那麼數據庫表中id爲1的用戶的金額就是-100了,在現實中是不允許的。強行扣款後的數據如圖:

這就是讀已提交,若有事務對數據進行更新操作時,讀操作事務要等待這個更新操作事務提交後才能讀取數據,可以解決髒讀問題。但在這個事例中,出現了一個事務範圍內兩個相同(刷卡時查詢和扣款時再次查詢)的查詢卻返回了不同數據,這就是不可重複讀

----------------------------------------------------------------------------------------------------------------------------

那麼如何解決不可重複讀?----->Repeatable read 可重複讀

可重複讀,就是在開始讀取數據(事務開啓)時,不再允許修改操作(insert/delete操作除外,這會出現一個新問題(幻讀)下面會講到)

比如用戶在刷卡時開啓了事務,這時用戶的女朋友就無法進行轉賬(update操作),這樣就防止了錢被用戶女朋友轉走的可能也就不會發生扣款失敗了。

1.將數據庫中的事務隔離級別修改爲Repeatable read,並左終端先扣1000元,先不提交,再右終端扣1000此時被阻塞了,因爲左終端還未提交。效果如圖:

 

 2.當左終端提交時,右終端才能執行(可以看到左終端先執行的update,而右終端再次執行就阻塞了,誰阻塞就說明前面有人比它先update操作具體的用戶,比如這兩個update都是id1)

重複讀可以解決不可重複讀問題。寫到這裏,應該明白的一點就是,不可重複讀對應的是修改,即UPDATE操作。但是可能還會有幻讀問題。因爲幻讀問題對應的是插入INSERT操作,而不是UPDATE操作。

幻讀:比如左終端開啓了一個事務要把所有用戶的信息打印,第一次查看的數據是隻有4個用戶,如下圖:

而在此時,右終端新增了一個用戶,並提交了事務,這個時候左終端再打印出來,就發現多了一個用戶(點擊打印的時候左終端已經把剛剛的事務提交了重新執行了一次select(不管此次有無事務),不然是看不到右終端新增的用戶的)。如下圖:

這個時候左終端就會發現難道我見鬼了????(可重複度(update操作)和幻讀(insert/delete操作)很像),那麼如何解決這種在頁面上顯示的數據(開啓了一個事務執行select)和打印的數據(又執行了一次select不管有無事務)不一致的情況呢?

Serializable 序列化 就是解決幻讀問題的,可重複讀是行級鎖,而Serializable是表級鎖,把整張表鎖住了。

把數據庫隔離級別設置未Serializable 再次執行重複度發生的問題,執行效果如圖:

 

 這樣就防止了打印和看到的結果不一致情況。

 

總結:Read uncommitted讀未提交(什麼都不能保障導致髒讀

        

Read committed 讀已提交(可以解決髒讀但會導致不可重複讀

Repeatable read 可重複讀(可以解決不可重複讀但會導致幻讀

Serializable 序列化 就是解決幻讀問題的,可重複讀是行級鎖,而Serializable是表級鎖。

mysql默認的事務隔離級別是Repeatable read 可重複讀。Serializable很少用到,因爲這會嚴重影響性能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章