mysql事物的隔離級別包括四種
READ_UNCOMMITTED spring實現讀未提交 (髒讀) 髒讀
READ_COMMITTED spring實現讀已提交 (待解決--不可重複讀+幻讀) 不可重複讀
REPEATABLE_READ spring實現可重複讀 (待解決--幻讀) 可重複讀
SERIALIZABLE spring實現串行化(已解決) 串行化
mysql默認爲不可重複讀,oracle默認爲可重複讀
髒讀和串行化使我們最容易理解的.假設現在有A、B兩個事務在運行。
髒讀:在A事務中sql讀取到了B中還沒有進行事務提交的數據。(如果B回滾,那麼A就讀到了錯誤的數據)
不可重複讀(你在一個事務中不能重複的讀取數據,否則結果出現問題):在A事務中不會讀取到B事務中還沒有提交的數據,避免了髒讀。但是在B事務完成提交後,A事務還沒有完成之前,A又去讀了數據,那麼A讀取的在B提交前後的數據是不一致的。
可重複讀(你在事務中可以重複的讀取數據):A事務在B事務提交前後讀取的數據一致。也就是說如果A事務在B事務提交前讀取了一次數據,那麼即使B已經更改了數據庫,但是A讀取到的,還是B事務提交之前的數據,這種會導致幻讀。
串行化:事務串行化,數據與數據庫一致。
思考:既然我們說 可重複讀 解決了不可重複讀的問題,也就是說我們在一個事務中讀取到的數據都是一致的,不會因爲別的事務提交的數據導致變化,那是不是就說明我們的事務將該行鎖住了,從而避免了其他行對該行的操作呢?
其實不是的,經測試可以看到,其實數據已經更改了,但是我們讀取的數據依然是以前的數據,這是爲什麼呢,這時因爲mysql採用了MVCC(多版本併發控制)方式。而這種方式讀取的數據會讀取快照(歷史版本),而不會讀取最新版本,但是insert update delete會對當前版本進行操作。
舉個簡單的例子,如果開啓可重複讀,你在A事務裏兩次讀取一個數據假設爲400,那麼在兩次讀取之間事務B更改了數據減去了50此時數據庫爲350,對A的讀取結果爲400沒有影響,但是如果你在事務A中再讓數據減去50那麼你再在事務A中查詢數據,數據就變成了300.因爲update語句會更新數據。
最後來說說 可重複讀 時mysql採用MVCC的實現機制。
其實挺簡單的。這裏值分析一下select的實現,具體的可以看下面的博文
其實在每行數據有面還有兩個列隱藏的行,一行是我們事務的版本號,一行是刪除的標誌
那麼我們上面說了,每次做增刪改的時候,這一行的事務版本號就會更新。
而MVCC告訴我們我們查詢出的數據,都必須滿足兩個條件,
a.InnoDB只會查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的.
b.行的刪除版本要麼未定義,要麼大於當前事務版本號,這可以確保事務讀取到的行,在事務開始之前未被刪除.
只有a,b同時滿足的記錄,才能返回作爲查詢結果.
那麼每次連接數據庫的時候開啓事務,他都會給你一個最新的版本號,假設A事務是讀取,那麼A事務在打開讀取了一次所有數據,那麼B事務開動增加一條數據,並提交,這時這條數據的事務版本號是高於A事務的事務版本好的,所以A再查詢也是查詢不到B事務提交的版本號的。
參考:
https://blog.csdn.net/whoamiyang/article/details/51901888
https://www.cnblogs.com/huanongying/p/7021555.html