mysql ACID以及隔離級別原理(innodb)

    一個被老生常談的問題,但是國內文章複製粘貼以及人云亦云太多,我算是做個總結。

一、髒讀、不可重複讀、幻讀

①髒讀:首先我們要知道mysql是可以支持事務併發執行的,那麼一個事務A查詢一條id=1,name=“java”數據,這時候另一個事務B對這條數據修改了,比如update user set name = "php" where id =1(但是還沒提交),這時候事務A去查詢就會查詢到name="php"的數據。這時候如果出於某種情況事務B回滾了,那麼A讀取到的數據就是髒數據。

②不可重複讀:跟第一個例子一樣,在一個事務A裏查詢一條id=1,name=“java”數據,這時候另一個事務B把name改成php !!!並且提交!!!,那麼當A再去讀取時候就會出現2次讀取不一樣的情況。

③幻讀:還是用上面的例子,在一個事務A裏查詢一條id=1,name=“java”數據,這時候另一個事務B插入一條id=2,name=“python”,這時候A再去查詢就會查到2條數據(id=2的稱爲幻行)。幻讀的情況比較多,這裏只列舉一個,後面原理會逐一講解。

總結:髒讀是發生在事務讀取到另一個事務未提交的數據;不可重複讀是發生在一個事務多次查詢之間另一個事務修改並提交了了數據,關鍵字update;幻讀是發生在一個事務多次操作之間另一個事務增刪並提交了數據,關鍵字insert、delete

二、隔離級別有哪幾種?分別什麼意思?

①READ UNCIMMITTED(未提交讀)

數據庫安全級別最低的,就是髒讀、不可重複讀、幻讀都不能防止。

②READ COMMITTED(提交讀)

故名思意,這個級別可以防止髒讀。

③REPEATABLE READ(可重複讀)重要!!!

innodb默認級別,也是今天講解的重點。這個級別不僅可以防止不可重複讀,也可以防止部分幻讀(要全部防止需要上鎖或者再提高級別,後面會祥講)。

④SERIALIZABLE(序列化)

最高級別,最簡單的查詢也會上鎖,保證所有情況的安全性,性能最差。

三、RR(REPEATABLE READ)級別如何防止不可重複讀

①先說4個概念:MVCC、undo log、快照讀、當前讀

undo log:任何修改(增刪改)都會將修改前的數據寫入到這個文件,作用是回滾時候就是用這個文件來回滾的。

MVCC:多版本控制。網上花裏胡哨說了很多,其實在我看來就是樂觀鎖的概念。在RR級別下,會在每個事務的第一條sql時候給這個事務一個事務id(cas方式)。也就是說如果你begin了,並不會馬上得到一個事務id,再根據id來判斷讀取最合適的數據(快照讀的實現原理)。注意:這個僅僅是在RR級別是這樣,RC不是這樣。

快照讀:不加for update(寫鎖)和lock in share mode(讀鎖)的select。他去查的時候會去做一個版本比較,到undo log裏去拿最合適的版本的數據

當前讀:加了or update(寫鎖)和lock in share mode(讀鎖)的select和增刪改。這個就是讀取最新的數據。

②RR如何防止不可重複讀?

這裏我們舉2個例子,相信大家就很快明白了。

假設表還是上面的user表,2個字段id、name,innodb,RR級別,表裏就一條數據id=1,name="java"!

(1)

第2行:事務A查出id=1,name="java"數據,並且獲取到事務id假設是1(我們追求的是原理及理解,不對具體id多少做深究)

第3行:事務B更新id=1數據但是還沒提交,這個時候獲取到的事務id假設是2,並且修改前的記錄(id=1,name="java")寫進undo log,在undo log裏的這條數據的事務id是1。

第6行:這個是關鍵了,也是MVCC的運用。他會查詢<=當前事務id的數據,也就是說只能讀取<=1的,事務A發現現在數據的事務id是2,不符合需求,去undo log裏拿(其實這裏我是說的簡單了,真正的這裏頭怎麼選擇最合適的版本是有一個算法的,有興趣的可以自己去百度),所以這樣拿出來的數據還是id=1,name="java"。

第8行:2個事務都提交了,再次去查詢就能查到id=1,name="php"的數據了。

 

(二)

第2行:B先執行,假設事務id=1

第4行:假設A事務id=2,按我們上面分析的,當前事務只能讀取到<=當前事務id的說法,A應該能讀取到<=2的已提交的數據。所以可以查出name="php"數據。

③RR級別怎麼防止幻讀?

這裏還是要說明,只有innodb的RR級別才能防止幻讀(要完全防止還是需要自己做一些操作)

首先要回到上面介紹幻讀是什麼時候有說到幻讀其實分很多種情況,而mysql官方只提及上面我介紹的情況,導致很多覺得只要解決了這個情況就是解決幻讀。下面我們按情況來分析,並且說明RR級別是怎麼防止幻讀。

(一)

這一種就是上面介紹的(快照讀),由於增刪,導致2次查詢發現數據多了或者少了的"幻行",具體原理應該不用解釋了吧,也是用MVCC解決。

(二)第二種情況是當前讀

首先我們要知道 next-key lock = gap + 行鎖(x+s)

原因很簡單,讀是讀快照讀,寫是當前讀,B的操作對A不可見,所以出現幻讀。要解決在第2行修改爲select * from user for update。使用next-key lock即可。

所以說RR級別其實並沒有完全解決幻讀,只是提供了方法(鎖)來解決。

更多關於鎖的博客https://dbaplus.cn/news-11-2518-1.html

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