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( 自己改的)
相關文章
- 檢視git當前版本號Git
- Logcat怎麼設定filter,檢視當前執行app的log資訊GCFilterAPP
- undo log和redo log
- 磁碟陣列檢視命令 RAID陣列AI
- 如何檢視Linux 當前訪問ipLinux
- Linux檢視環境變數當前資訊和檢視命令Linux變數
- InnoDB undo log原理
- 檢視當前pg會話連線數會話
- git 檢視當前分支指向提交物件SHA值Git物件
- MySQL中的redo log和undo logMySql
- MySQL Undo Log和Redo Log介紹MySql
- 8.2 快照讀,當前讀
- 【Mysql】三大日誌 redo log、bin log、undo logMySql
- 輸出當前分支的最新commit IDMIT
- NumPy 陣列複製與檢視詳解陣列
- Solr Transaction Log(Tlog)的作用Solr
- 17_深入解析Oracle undo原理(1)_transactionOracle
- Linux檢視當前目錄下的檔案大小Linux
- Python 檢視當前環境所有變數的大小Python變數
- 使用sestatus命令來檢視SELinux的當前狀態Linux
- MySQL Binlogging Fails With Writing One Row To The Row-based Binary Log FailedMySqlAI
- 檢視linux系統當前登陸的使用者Linux
- Java 例項 - 如何檢視當前 Java 執行的版本?Java
- android檢視當前應用的的包名和activityAndroid
- 檢測陣列更新陣列
- InnoDB文件筆記(三)—— Undo Log筆記
- mysql獲取指定表當前自增id值MySql
- 在Linux中,如何檢視當前系統的版本資訊?Linux
- Centos下檢視當前目錄大小及檔案個數CentOS
- MySQL必知必會:簡介undo log、truncate、以及undo log如何幫你回滾事物MySql
- 硬核乾貨!一文掌握 binlog 、redo log、undo log
- MySQL中redo log、undo log、binlog關係以及區別MySql
- mysql日誌:redo log、binlog、undo log 區別與作用MySql
- 深入理解MySQL系列之redo log、undo log和binlogMySql
- MySQL中undo log介紹及清理MySql
- InnoDB purge原理--哪些undo log可purge
- Linux 下檢視系統當前登入使用者資訊Linux
- 1.4.2. 檢查當前版本號