您好,登錄后才能下訂單哦!
mysql如何實現隔離級別?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
隔離級別
事務指定一個隔離級別,該隔離級別定義一個事務必須與由其他事務進行的資源或數據更改相隔離的程度。隔離級別從允許的并發副作用(例如,臟讀或幻讀)的角度進行描述。
控制內容:
讀取數據時是否占用鎖以及所請求的鎖類型。
占用讀取鎖的時間。
引用其他事務修改的行的讀取操作是否:
在該行上的排他鎖被釋放之前阻塞其他事務。
檢索在啟動語句或事務時存在的行的已提交版本。
讀取未提交的數據修改。
隔離級別的實現:
未提交讀(RU:read-uncommitted):
在RU級別中,事務讀到的所有數據都是最新的數據,可能是事務提交后的數據,也可能是事務執行中的數據(可能會被回滾)。
當隔離級別為RU時:
所有的讀不加鎖,讀到的數據都是最新的數據,性能最好。
所有的寫加行級鎖,寫完釋放。
提交讀(RC:read-committed):
使用MVCC技術,在每一行加入隱藏的字段(DB_TRX_ID:修改該行的最后一個事務的id,DB_ROLL_PTR:指向當前行的undo log日志,DB_ROW_ID:行標識,DELETE_BIT:刪除標志),它實現了不加鎖的讀操作。
當隔離級別為RC時:
寫操作:加行級鎖。事務開始后,會在UNDO日志中寫入修改記錄,數據行中的隱藏列DATA_POLL_PTR存儲指向該行的UNDO記錄的指針。
讀操作:不加鎖。在讀取時,如果該行被其它事務鎖定,則順著隱藏列DATA_POLL_PTR指針,找到上一個有效的歷史記錄(有效的記錄:該記錄對當前事務可見,且DELETE_BIT=0)。
可重復讀(RR:repeatable-read):
使用MVCC技術來實現不加鎖的讀操作。
當隔離級別為RR時:
寫操作:加行級鎖。事務開始后,會在UNDO日志中寫入修改記錄,數據行中的隱藏列DATA_POLL_PTR存儲指向該行的UNDO記錄的指針。
讀操作:不加鎖。在讀取時,如果該行被其它事務鎖定,則順著隱藏列DATA_POLL_PTR指針,找到上一個有效的歷史記錄(有效的記錄:該記錄對當前事務可見,且DELETE_BIT=0)。
從上面可以知道:實際上RC和RR級別的操作基本相同,而不同之處在于:行記錄對于當前事務的可見性(可見性:即哪個版本的行記錄對這個事務是可見的)。RC級別對數據的可見性是該數據的最新記錄,RR基本對數據的可見性是事務開始時,該數據的記錄。
(1)行記錄的可見性(read_view)的實現
在innodb中,創建一個事務的時候,會將當前系統中的活躍事務列表創建一個副本(read_view),里面存儲著的都是在當前事務開始時,還沒commit的事務,這些事務里的值對當前事務不可見。
read_view中有兩個關鍵值 up_limit_id(當前未提交事務的最小版本號-1,在up_limit_id之前的事務都已經提交,在up_limit_id之后的事務可能提交,可能還沒提交) 和 low_limit_id(當前系統尚未分配的下一個事務id,也就是目前已出現過的事務id的最大值+1。注意:low_limit_id不是最大的活躍事務的id。)
注意:當前事務和正在commit的事務是不在read_view中的。
(2)無論是RC級別還是RR級別,其判斷行記錄的可見性的邏輯是一樣的。
當該事務要讀取undo中的行記錄時,會將行記錄的版本號(DB_TRX_ID)與read_view進行比較:
1、如果DB_TRX_ID小于up_limit_id,表示該行記錄在當前事務開始前就已經提交了,并且DELETE_BIT=0,則該行記錄對當前事務是可見的。
2、如果DB_TRX_ID大于low_limit_id,表示該行記錄在所在的事務在本次事務創建后才啟動的,所以該行記錄的當前值不可見。
3、如果up_limit_id< = DB_TRX_ID <= low_limit_id,判斷DB_TRX_ID是否在活躍事務鏈中,如果在就是不可見,如果不在就是可見的。
4、如果上面判斷都是不可見的,則讀取undo中該行記錄的上一條行記錄,繼續進行判斷。
而對于RC級別的語句級快照和RR級別的事務級快照的之間的區別,其實是由read_view生成的時機來實現的。
RC級別在執行語句時,會先關閉原來的read_view,重新生成新的read_view。而RR級別的read_view則只在事務開始時創建的。所以RU級別每次獲取到的都是最新的數據,而RR級別獲取到的是事務開始時的數據。
(3)值得注意的是: 在上面的可見性判斷中,雖然邏輯是一樣的,但是實際意義上是有區別的:
在第二步中,對于RC級別來說,low_limit_id是執行語句時已出現的最大事務id+1,可以認為在執行語句時,是不存在事務會比low_limit_id要大,所以大于low_limit_id的事務都是不可見的。
而對于RR級別來說,low_limit_id是當前事務開始時已出現的最大事務+1(也可以認為是當前事務的id+1,因為在創建當前事務時,當前事務的id最大),大于low_limit_id的事務表示是在該事務開始后創建的,所以對RR級別是不可見。
在第三步中,對于RC級別來說,只要DB_TRX_ID不在活躍鏈表中,則無論DB_TRX_ID是否大于事務id,RC都是可見的。
而對于RR級別來說,因為low_limit_id就是當前事務id+1,可以認為小于low_limit_id的事務都是在當前事務創建前出現的,所以也只需要簡單判斷DB_TRX_ID是否在活躍鏈表中。
串行化(serializable):讀寫都會加鎖
關于mysql如何實現隔離級別問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。