mysql的隔離級別是如何實現的

mysql的隔離級別的實現方法:當隔離級別為未提交讀時,所有的讀不加鎖,讀到的數據都是最新的數據,性能最好,所有的寫加行級鎖,寫完釋放。當隔離級別為串行化時,讀寫都會加鎖。

mysql的隔離級別是如何實現的

隔離級別

(推薦教程:mysql教程

數據庫事務的隔離級別有4個,由低到高依次為Read uncommitted(讀未提交)、Read committed(讀提交)、Repeatable read(可重復讀取)、Serializable(可串行化),這四個級別可以逐個解決臟讀、不可重復讀、幻象讀這幾類問題。

隔離級別的實現:

未提交讀(RU:read-uncommitted):

在RU級別中,事務讀到的所有數據都是最新的數據,可能是事務提交后的數據,也可能是事務執(zhí)行中的數據(可能會被回滾)。

當隔離級別為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中,創(chuàng)建一個事務的時候,會將當前系統(tǒng)中的活躍事務列表創(chuàng)建一個副本(read_view),里面存儲著的都是在當前事務開始時,還沒commit的事務,這些事務里的值對當前事務不可見。

read_view中有兩個關鍵值 up_limit_id(當前未提交事務的最小版本號-1,在up_limit_id之前的事務都已經提交,在up_limit_id之后的事務可能提交,可能還沒提交) 和 low_limit_id(當前系統(tǒng)尚未分配的下一個事務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,表示該行記錄在所在的事務在本次事務創(chuàng)建后才啟動的,所以該行記錄的當前值不可見。

3、如果up_limit_id

4、如果上面判斷都是不可見的,則讀取undo中該行記錄的上一條行記錄,繼續(xù)進行判斷。

而對于RC級別的語句級快照和RR級別的事務級快照的之間的區(qū)別,其實是由read_view生成的時機來實現的。

RC級別在執(zhí)行語句時,會先關閉原來的read_view,重新生成新的read_view。而RR級別的read_view則只在事務開始時創(chuàng)建的。所以RU級別每次獲取到的都是最新的數據,而RR級別獲取到的是事務開始時的數據。

(3)值得注意的是: 在上面的可見性判斷中,雖然邏輯是一樣的,但是實際意義上是有區(qū)別的:

在第二步中,對于RC級別來說,low_limit_id是執(zhí)行語句時已出現的最大事務id+1,可以認為在執(zhí)行語句時,是不存在事務會比low_limit_id要大,所以大于low_limit_id的事務都是不可見的。

而對于RR級別來說,low_limit_id是當前事務開始時已出現的最大事務+1(也可以認為是當前事務的id+1,因為在創(chuàng)建當前事務時,當前事務的id最大),大于low_limit_id的事務表示是在該事務開始后創(chuàng)建的,所以對RR級別是不可見。

在第三步中,對于RC級別來說,只要DB_TRX_ID不在活躍鏈表中,則無論DB_TRX_ID是否大于事務id,RC都是可見的。

而對于RR級別來說,因為low_limit_id就是當前事務id+1,可以認為小于low_limit_id的事務都是在當前事務創(chuàng)建前出現的,所以也只需要簡單判斷DB_TRX_ID是否在活躍鏈表中。

串行化(serializable):讀寫都會加鎖

以上就是

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享