當多個數據庫事務同時運行,其修改數據產生的中間狀態對於其餘事務的可見性是數據庫隔離級別來限制的,而這個可見性的約束有四種sql
其中讀未提交最弱,多個事務共享一份數據就行了,而串行化最強,讀取加讀鎖,寫數據加寫鎖,而讀已提交和可重複讀都須要有「不讀取未提交的數據」和「只讀取建立事務以前的數據」這樣的需求,而實現這樣的需求,天然而然的想到要引入「快照」的概念,也就是對數據庫的每一行,併發修改的時候生成快照,在MySQL,快照的實現藉助的是MVCC,即多版本併發控制,下面將主要圍繞快照如何組織,以及如何使用快照兩個部分對MVCC進行描述。數據庫
MySQL的快照依賴的是版本鏈,也就是UndoLog,UndoLog在每次修改數據的時候,保留數據最初始的版本,同時記錄最新版,既然是鏈,就有指針,這個指針在每行數據的隱藏字段當中,同時,每次修改的快照天然須要記錄是誰修改的,這個誰就是事務,事務有本身的惟一,自增的事務Id,惟一是標識事務的必要條件,而自增,則給了事務Id順序性的含義,順序的ID對於以後使用快照的階段很是重要,固然事務Id和undo指針同樣都在每行數據的隱藏字段當中。markdown
其中trx_id
就是事務Id,roll_p
就是指針併發
若是有一條記錄爲A,通過了以下的操做oop
事務2 | 事務3 |
---|---|
begin; |
|
將A修改成B |
begin; |
將B修改成C (時刻1) |
|
commit; |
|
commit; |
那麼在時刻1的版本鏈以下所示:spa
如今版本鏈已經有了,可是如何使用,只靠一個版本鏈是缺少足夠的信息來實現讀已提交和可重複讀的,咱們還缺少在事務建立的一些額外的信息,就比如,讀已提交須要知道什麼是已提交,進一步,哪些事務是已提交的,等等,這些信息構成了使用MVCC的運行時上下文,下面咱們總結下MVCC使用的上下文信息。線程
建立快照的時候也須要記錄一些建立時刻的基本信息,好比建立事務的時刻,有哪些事務正在運行,這些數據方便界定哪些事務是已經提交了的,我能夠讀了,也須要當前事務的事務Id,也須要在建立快照的那一剎那,標識對於當前的事務而言,哪些事務對於當前的事務是不可見的將來。對於這些數據,以下圖所示:指針
其中m_ids
表示建立事務的那一刻,當前運行中的事務,creator_trx_id
表示建立者事務,min_trx_id
是m_ids
的最小值,小於min_trx_id
的事務Id對當前事務而言是妥妥的已提交,而max_trx_id
是當前事務Id的下一個Id。code
快照如何工做,主要依賴以上描述的信息搭配undoLog鏈:orm
trx_id
屬性值creator_trx_id
相同,則是本身的記錄,可見trx_id
小於min_trx_id
則表明該記錄已經提交,可見trx_id
大於等於max_trx_id
則是建立該視圖以後的事務,不可見trx_id
處於min_trx_id
和max_trx_id
之間,則須要判斷此時此刻trx_id
是否在m_ids
之間,若是依然在,則不可見。上面描述的基本信息包含在一次讀視圖中(ReadView)
因爲MVCC版本鏈的機制,可見爲了支持MVCC,更新的數據能夠和老數據同時留存,刪除的數據也不會當即刪除,而是打上刪除標記,所以必定要注意長事務對於MySQL自己的影響
在開發過程當中,能夠設置set autocommit=1
查詢長事務能夠經過以下的語句來查看:
select
*
from information_schema.innodb_trx
where
TIME_TO_SEC(timediff(now(),trx_started))>60
複製代碼