由淺到深讓你明白 MySQL 的事務
什么是事務
事務(Transaction)是并發控制的基本單位。所謂的事務呢,它是一個操作序列,這些操作要么都執行,要么都不執行,它是一個不可分割的工作單位。為什么?因為事務是數據庫維護數據一致性的單位,在每一個事務結束的時候都能保持數據的一致性,如像積分表和積分詳情表一起更新要么就成功,要么就失敗。
事務的四大特性ACID
「原子性(Atomicity):」 原子性是指整個數據庫的事務是一個不可分割的工作單位,在每一個都應該是原子操作。當我們執行一個事務的時候,如果在一系列的操作中,有一個操作失敗了,那么需要將這一個事務中的所有操作恢復到執行事務之前的狀態,這就是事務的原子性。
「一致性(Consistency):」 一致性呢是指事務將數據庫從一種狀態轉變成為下一種一致性的狀態,也就是說是在事務的執行前后,這兩種狀態應該是一樣的,也就是在數據庫的完整性約束不會被破壞。另外的話,還需要注意的是一致性不關注中間的過程是發生了什么。
「隔離性(lsolation):」 Mysql數據庫可以同時的話啟動很多的事務,但是呢,事務跟事務之間他們是相互分離的,也就是互不影響的,這就是事務的隔離性。
「持久性(Durability):」 事務的持久性是指事務一旦提交,就是永久的了。說白了就是發生了問題,數據庫也是可以恢復的。因此持久性保證事務的高可靠性。
Mysql事務隔離級別
「Read uncommitted(讀取未提交的數據):」 即便是事務沒有commit,但是其他連接任然能讀到未提交的數據,這個事務隔離級別是等級最低的。
「Read committed(可以讀取其他事務提交的數據):」 當前會話只能讀取到其他事務提交的數據,沒有提交的數據是讀取不到的。
「Repeatable read(可重讀):」 這個是Mysql的默認隔離級別:當前會話可以重復讀,就是每次讀取到的結果集都是相同的,不管其他的事務有沒有提交。
「Serializable(串行化):」 其他會話對該表的寫操作將會被掛起,可以看到,這個是隔離級別里最為嚴格的,但是這樣做勢必會對性能造成影響
設置事務隔離級別的代碼是
- set session transaction isolation level serializable;
一個數據庫事務通常的話包含了一個序列對數據庫的讀/寫操作,它的存在主要是包含有以下兩個目的:
第一,為數據庫操作序列提供了一個從失敗中恢復到正常狀態的方法,同時呢也提供了數據庫即使在異常狀態下仍然能夠保持一致性的方法。
第二,當多個應用程序在并發訪問數據庫的時候,可以在這些應用程序之間提供一個隔離的方法,以防止彼此的操作相互干擾對方。
并發事務導致的問題
在許多的事務同時處理一個數據的時候,如果沒有采取有效的隔離機制的話,那么并發處理數據的時候,會帶來一些問題。
「臟讀:」 臟讀是指在一個事務的處理過程中讀取了另外一個沒有提交事務里的數據。
「幻讀:」 也叫虛讀是指在一個事務執行了兩次查詢,第二次的結果集包含了第一次中沒有或者是某些行已被刪除的數據,造成了兩次的結果不一致,只是呢另一個事務在這兩次查詢中間插入或者是刪除造成的。幻讀是一種事務非獨立執行時發生的。
「不可復讀:」 一個事務兩次讀取了同一行的數據,結果得到了不同狀態的結果,中間過程的時候正好有其另外一個事務更新了這個數據,兩個結果不一樣,不可被信任。
Mysql數據執行過程剖析
Buffer Pool是什么?
Buffer Pool就是數據庫的一個內存組件,緩存了磁盤上的真實數據,我們的系統對數據庫執行增刪改查操作其實呢就是主要對這個內存數據結構中的緩存數據執行的。
Mysql的RedoLog和UnidoLog日志
InnoDB使用了undolog、redolog來保證了事務的原子性、一致性與持久性,同時的話采用了預寫日志的方式將隨機寫入變成順序追加寫入,從而提升了事務的性能。
「undo log:」 它就是作用于記錄事前變更前的狀態,在對數據進行操作之前,會先把數據備份到undu log,然后再進行數據的修改,如果出現錯誤或者是用戶執行了rollback語句,則系統就可以利用undo log里備份的數據恢復到事務開始之前的狀態。undo log日志是一種邏輯格式的日志,在執行undo的時候,僅僅是將數據從邏輯上恢復到事務之前的狀態,而不是從物理頁面上操作實現的。undo log位于數據庫的data目錄下的ibdata。
「redo log:」 它的作用就是記錄事務變更后的狀態。在提交事務之前,只要把redo log持久化就可以了,數據就在內存中變更。當系統崩潰的時候,雖然數據沒有了落盤,但是redo log已經持久化了,系統就可以根據redo log的內容,把所有的數據恢復到最新的狀態。redo log是一種物理格式的日志,記錄的是物理數據頁面的修改信息,其中redo log是順序寫入redo log file的物理文件中去的。它位于數據庫的data目錄下的ib_logfile1&ib_logfile2下。
「checkpoint:」 redo log會隨著時間的積累,redo log就會變得很大很大。如果每一次都從第一條記錄開始恢復數據的話,那么恢復的過程是漫長的。所以為了節省恢復時間,就引入了checkpoint機制,它會定期將databuffer的內容刷新到磁盤的datafile內,然后再清除掉checkpoint之前的redo log。其實就是InnoDB通過加載最新的快照,然后重做checkpoint之后所有的事務(包括了未提交和回滾的),然后再通過undo log來回滾那些未提交的事務來完成對數據的恢復。
MySQL的事務MVCC結構
InnoDB Multi-Versionnoing-InnoDB是多版本的存儲引擎:它保留了有關已經更改行的舊版本信息,以支持并發和rollback的事務功能。像此類的信息稱為rollback segment的數據結構存儲在table空間當中。它的實現原理就是InnoDB向存儲在數據庫里的每一行添加兩個關鍵的字段:DATA_TRX_ID和DATA_ROLL_PTR。
「DATA_TRX_ID:」 DATA_TRX_ID是標記了最新更新這條行數據的transaction id,每處理一個事務,值會自動+1。
「DATA_ROLL_PTR:」 表示了指向該行回滾段的指針,該行上所有舊的版本,在undo中都有通過鏈表的形式組織,而該值,正式指向undo中該行的歷史記錄鏈表。
MVCC
MVCC的目的就是多版本并發控制,在數據庫的實現,就是為了解決讀寫沖突,它的實現原理主要依賴記錄中的隱式(DATA_TRX_ID、DATA_ROLL_PTR、Read View)字段。undo log,Read View來實現的。InnoDB MVCC的實現基于undo log,通過回滾指針來構建需要的版本記錄。通過Read View來判斷哪一些版本的數據可見。
MVCC的作用
1、每一行的數據都會存在一個版本,每一次的數據更新的時候都會更新該版本。
2、修改時Copy出當前版本隨意修改,各個事務之間無干擾。
3、把修改前的數據存放于undo log,通過回滾指針的主數據關聯。
4、修改成功(commit)啥都不做,失敗的話就回復undo log中的數據(rollback)
「Read View:」 它是一個數據結構,在SQL開始的時候被創建。這個數據結構里有三個主要的成員分別是low_trx_id、up_trx_id、trx_ids,在并發的情況下,一個事務在啟動的時候,trx_sys鏈表里存儲部分還未提交的事務,那么哪些改變對當前的事務是可見的,哪些又是不可見的,這個就需要通過這個ReadView來進行判定了。
low_trx_id:表示的是該SQL啟動的時候,當前事務鏈表中最大的事務id編號,也就是最近創建的除自身以外最大的事務編號。
up_trx_id:表示的是該SQL啟動的時候,當前的事務鏈表中最小的事務id編號,也就是當前系統里創建最早但是還沒有提交的事務。
trx_ids:表示所有的事務鏈表里事務id的集合。
「ReadView讀取的區別:」 READ COMMITTED 是每次讀取數據前都生成一個ReadView,REPEATABLE READ 是在第一次讀取數據時生成一個ReadView