8. transaction id,row trx_id,undo log,檢視陣列,當前讀
事務號 transaction id, undo log
InnoDB 裡面每個事務有一個唯一的事務 ID, transaction id。它是在事務開始的時候(第一個操作)向 InnoDB 的事務系統申請的,是按申請順序嚴格遞增的。
資料表中的一行記錄,可能有多個版本 (row)。每個版本是每次事務更新資料的時候產生的, 每個版本有個row trx_id, 就是 transaction id . 同時,舊的資料版本要保留,並且在新的資料版本中,可以訪問到老的版本(通過undo log )
如: 當前最新版本是 V4,k 的值是 22,它是被 transaction id = 25 的事務更新的,因此它的 row trx_id 也是 25。
U1,U2,U3 這些箭頭就是 undo log
V1、V2、V3 並不真實存在的,
而是每次需要的時候根據當前版本和 undo log (箭頭後退)計算出來的。
一致性檢視(read-view)
可重複讀 (mysql預設隔離級別):
資料庫裡在事務啟動時建立一個檢視,
(start transaction with consistent snapshot;
開始檢視, 這句只有在可重複讀時有效, 讀提交 時 只是普通的開始事務)
整個事務存在期間看到的值都用這個檢視。
就是 這個事務啟動的時刻為準,如果一個資料版本(row trx_id)是在啟動之前生成的,就不可見, 繼續往前找( 用undo log回退 )。
在實現上, InnoDB 為每個事務構造了一個陣列,用來儲存這個事務啟動瞬間,當前正在“活躍”(事務啟動並還沒提交)的所有事務 ID, 這些事務雖然在本事務之前,但是還沒提交,之後也可能更新
陣列裡面事務 ID 的最小值記為低水位,
當前系統裡面已經建立過的事務 ID 的最大值加 1 記為高水位
高水位不一定是自己, 因為事務啟動申請自己的事務 和 構造這個陣列 之間有時間差, 可能有其他事務產生
start transaction;之後
第一次操作才產生檢視,
start transaction; 和select之間有其他事務的更新提交了, 會被算做之後的事務,納入本事務快照讀承認的快照
就是當前事務的 一致性檢視(read-view)。
對於當前事務的,一行資料版本的 row trx_id,有以下幾種可能:
1.綠色: 我開始前提交的,直接可見
2.紅色: 我開始後開始的,直接不可見
3.黃色, 需要查陣列,
陣列裡面: 我開始時還沒提交 不可見
不在裡面就可見
因為先開始的事務,不一定先提交, 在黃色區域的 事務7在本事務開始前提交了(可見),在他之前的事務6卻沒有提交
這樣分3段就可以迅速判斷一下, 在黃色區域再進一步查資料
例子
事務 A 開始前,系統裡面只有一個活躍事務 ID 是 99;
事務 A、B、C 的版本號分別是 100、101、102,且當前系統裡只有這四個事務;
三個事務開始前,(1,1)這一行資料的 row trx_id 是 90。
事務 A(100) 陣列: [99,100], 低水位99 高水位100
事務 B(101) 陣列: [99,100,101], 低水位99 ,高水位102
事務 C(102) 陣列: [99,100,101,102]. 低水位99.高水位102
A事務(100) 陣列: [99,100]:
雖然最先開始,但是做了其他的事,最後來讀取這行
查詢語句的讀資料流程是這樣的:
找到最新的 (1,3) 的時候, row trx_id=101,比高水位100大,不可見;
undo log 往前找,找到上一個歷史版本,一看 row trx_id=102,比高水位100大,不可見;
undo log 往前找,找到了(1,1),它的 row trx_id=90,比低水位99小,處於綠色區域,可見
A事務(100) 什麼時候讀都是(1,1),看到這行資料的結果都是一致的,所以我們稱之為一致性讀。
當前讀
更新資料, 不能再讀檢視的資料來更新了, 不然就不對了, 因此只能讀當前的值,稱為“當前讀”(current read)
當前讀: 必須讀最新版本, 如果最新版本的另一個事務沒提交, 本事務只能堵塞 等他提交 再接著執行, 並且對自己讀到的資料加鎖 不讓其他事務改
select...lock in share mode ,(共享鎖)
select...for update(排他鎖)
update , delete , insert(排他鎖)
這些都是當前讀,就是加鎖, 會阻塞
事務B(101),如果在更新之前插一句讀取此行的資料 會讀到1, 因為事務c(102)的修改對它不可見,
但是事務B(101) 的+1修改, 必須基於最新的資料(1,2), 不然就丟失事務c(102)的更新了
更新資料都是先讀後寫的,而這個讀,只能讀當前的值,稱為“當前讀”(current read)。
select 語句如果加鎖,也是當前讀
事務 A (100)的查詢語句 select * from t where id=1 修改一下,加上
lock in share mode :讀鎖(S 鎖,共享鎖)mysql> select k from t where id=1 lock in share mode;
for update:寫鎖(X 鎖,排他鎖)mysql> select k from t where id=1 for update;
也都可以讀到版本號是 101 的資料,返回的 k 的值是 3。
事務 B (101),查詢時,一看自己的版本號是 101,最新資料的版本號也是 101,是自己的更新,可以直接使用,所以查詢得到的 k 的值是 3。
行鎖
如果上面事務C 改成 update後不馬上commit, 在事務B update後 事務C 才commit
事務 C’沒提交,也就是說 (1,2) 這個版本上的寫鎖還沒釋放。而事務 B 是當前讀(更新),必須要讀最新版本,而且必須加鎖,因此就被鎖住了,必須等到事務 C’釋放這個鎖,才能繼續它的當前讀。
讀提交情況下
每一個語句執行前都會重新算出一個新的檢視。
"start transaction with consistent snapshot; " 無效, 只相當於start transaction
開始事務
事務 A .查詢語句的檢視陣列 執行這個語句的時候建立的,時序上 (1,2)、(1,3) 的生成時間都在建立這個檢視陣列的時刻之前。但是:
(1,3) 還沒提交,屬於情況 1,不可見;
(1,2) 提交了,屬於情況 3,可見。
所以,這時候事務 A 查詢語句返回的是 k=2。
事務 B 查詢結果 k=3( 自己改的)
相關文章
- 檢視當前會話session id方法:會話Session
- 磁碟陣列檢視命令 RAID陣列AI
- 檢視oracle當前sessionOracleSession
- 用mysqlbinlog檢視row格式的事件MySql事件
- 檢視git當前版本號Git
- 檢視當前系統程式
- Logcat怎麼設定filter,檢視當前執行app的log資訊GCFilterAPP
- Oracle 檢視當前會話 SESSION ID 方法 說明Oracle會話Session
- MySQL檢視當前資料庫庫MySql資料庫
- android檢視當前應用的的包名和activityAndroid
- 【轉載】檢視當前會話SID的三種方法會話
- Linux檢視環境變數當前資訊和檢視命令Linux變數
- 檢視Linux系統是否使用RAID陣列資訊LinuxAI陣列
- 檢視當前pg會話連線數會話
- 檢視當前使用者正在等待事件事件
- 檢視當前windows使用的字符集Windows
- 檢視當前linux的核心版本(轉)Linux
- linux下檢視當前網路流量Linux
- 如何檢視Linux 當前訪問ipLinux
- oracle檢視flashback_transaction_query中列operation為unknownOracle
- jQuery將當前陣列根據一定規則轉為其他陣列jQuery陣列
- git 檢視當前分支指向提交物件SHA值Git物件
- 檢視當前Windows系統CMD所有的命令Windows
- 檢視當前最消耗CPU/Memory的oracle程式Oracle
- 檢視當前jdk能支援的字符集JDK
- 如何檢視資料庫當前的狀態?資料庫
- 使用MegaCli工具檢視Raid磁碟陣列狀態[主站備]AI陣列
- 檢視當前系統程式指令碼ps.sh指令碼
- 如何實時檢視mysql當前連線數? 薦MySql
- 【轉】檢視Oracle當前使用者下的資訊Oracle
- vue陣列物件修改觸發檢視更新Vue陣列物件
- 【AIX】AIX系統下檢視磁碟陣列AI陣列
- NumPy 陣列複製與檢視詳解陣列
- 使用sestatus命令來檢視SELinux的當前狀態Linux
- Java 例項 - 如何檢視當前 Java 執行的版本?Java
- Linux檢視和剔除當前登入使用者Linux
- 檢視當前使用者執行語句等資訊
- 檢視當前oracle中正在執行的sql語句OracleSQL