mysql的隔離等級的實作方法:當隔離等級為未提交讀取時,所有的讀不加鎖,所讀到的資料都是最新的數據,效能最好,所有的寫加行級鎖,寫完釋放。當隔離等級為串列化時,讀寫都會加鎖。
隔離等級
#(推薦教學:mysql教學)
資料庫事務的隔離等級有4個,由低到高依序為Read uncommitted(讀取未提交)、Read committed(讀取提交)、Repeatable read(可重複讀取)、Serializable(可串列化),這四個等級可以逐一解決髒讀、不可重複讀、幻象讀這幾類問題。
隔離等級的實作:
未提交讀取(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的隔離等級是如何實現的的詳細內容。更多資訊請關注PHP中文網其他相關文章!