MySQL 的事物管理

2021-10-13 17:13:48 字數 3872 閱讀 3031

在mysql中,如果每次的更新操作都需要寫進磁碟,然後磁碟也要找到對應的那條記錄,然後再更新,整個過程io成本、查詢成本都很高。mysql裡常說的wal技術,全稱是write-ahead logging,它的關鍵點就是先寫日誌,再寫磁碟

redo log是innodb儲存引擎層的日誌,又稱重做日誌檔案,用於記錄事務操作的變化,記錄的是資料修改之後的值,不管事務是否提交都會記錄下來。在例項和介質失敗(media failure)時,redo log檔案就能派上用場,如資料庫掉電,innodb儲存引擎會使用redo log恢復到掉電前的時刻,以此來保證資料的完整性。

當有一條記錄需要更新的時候,innodb引擎就會把記錄寫到redo log裡面,並更新buffer pool的page,這個時候更新就算完成了

buffer pool是物理頁的快取,對innodb的任何修改操作都會首先在buffer pool的page上進行,然後這樣的頁面將被標記為臟頁並被放到專門的flush list上,後續將由專門的刷髒執行緒階段性的將這些頁面寫入磁碟

innodb的redo log是固定大小的,比如可以配置為一組4個檔案,每個檔案的大小是1gb,從頭開始寫,寫到末尾就又回到開頭迴圈寫

write pos是當前記錄的位置,一邊寫一邊後移,寫到第3號檔案末尾後就回到0號檔案開頭。check point是當前要擦除的位置,也是往後推移並且迴圈的,擦除記錄前要把記錄更新到資料檔案

write pos和check point之間空著的部分,可以用來記錄新的操作。如果write pos追上check point,這時候不能再執行新的更新,需要停下來擦掉一些記錄,把check point推進一下

有了redo log,innodb就可以保證即使資料庫發生異常重啟,之前提交的記錄都不會丟失,這個能力成為crash-safe

undo log是為了實現事物的原子性,在mysql資料庫innodb儲存引擎中,還用undo log 來實現多版本併發控制(簡稱:mvcc)

在操作任何資料前,首先將資料備份到乙個地方(這個儲存資料備份的地方稱為undo log),然後進行資料的修改,如果出現錯誤或者使用者執行了rollback語句,系統可以利用undo log中的備份將資料恢復到事物開始之前的狀態

注意:undo log是邏輯日誌,可以理解為:

當delete一條記錄時,undo log中會記錄一條對應的insert記錄

當insert一條記錄時,undo log中會記錄一條對應的delete記錄

當update一條記錄時,它記錄一條對應的反向update記錄

當有多個請求來讀取表中的資料時可以不採取任何操作,但是多個請求裡有讀請求,又有修改請求時必須有一種措施來進行併發控制。不然很有可能會造成不一致。

讀寫鎖

解決上述問題很簡單,只需用兩種鎖的組合來對讀寫請求進行控制即可,這兩種鎖被稱為:

共享鎖(shared lock),又叫做"讀鎖"

讀鎖是可以共享的,或者說多個讀請求可以共享一把鎖讀資料,不會造成阻塞。

排他鎖(exclusive lock),又叫做"寫鎖"

寫鎖會排斥其他所有獲取鎖的請求,一直阻塞,直到寫入完成釋放鎖。

mvcc (multiversion concurrency control) 叫做多版本併發控制。

innodb的 mvcc ,是通過在每行記錄的後面儲存兩個隱藏的列來實現的。這兩個列,乙個儲存了行的建立時間,乙個儲存了行的過期時間,當然儲存的並不是實際的時間值,而是系統版本號。

mvcc在mysql中的實現依賴的是undo log與read view前面講的重做日誌,回滾日誌以及鎖技術就是實現事務的基礎。

原子性,永續性,隔離性折騰半天的目的也是為了保障資料的一致性!

乙個事務必須被視為不可分割的最小工作單位,乙個事務中的所有操作要麼全部成功提交,要麼全部失敗回滾,對於乙個事務來說不可能只執行其中的部分操作,這就是事務的原子性。

那麼資料庫是怎麼實現的呢? 就是通過回滾操作。

所謂回滾操作就是當發生錯誤異常或者顯式的執行rollback語句時需要把資料還原到原先的模樣,所以這時候就需要用到undo log來進行回滾,接下來看一下undo log在實現事務原子性時怎麼發揮作用的

每條資料變更(insert/update/delete)操作都伴隨一條undo log的生成,並且回滾日誌必須先於資料持久化到磁碟上,對應的邏輯如下:

當delete一條記錄時,undo log中會記錄一條對應的insert記錄

當insert一條記錄時,undo log中會記錄一條對應的delete記錄

當update一條記錄時,它記錄一條對應的反向update記錄

mysql的innodb儲存引擎,使用redo log保證了事務的永續性。

當事務提交時,必須先將事務的所有日誌寫入日誌檔案進行持久化,就是我們常說的wal(write ahead log)機制(這個技術是保障永續性的關鍵技術)。這樣才能保證斷電或宕機等情況發生後,已提交的事務不會丟失,這個能力稱為 crash-safe。

read uncommited (未提交讀)

讀最新的資料,不管這條記錄是不是已提交。不會遍歷版本鏈,少了查詢可見的版本的步驟。這樣可能會導致髒讀。

對寫仍需要鎖定,策略和讀已提交類似,避免髒寫。

read commited (提交讀)

mysql的讀已提交實際是語句級別快照。

與可重複讀級別主要有兩點不同:

獲得readview的時機。每個語句開始執行時,獲得readview,可見性判斷是基於語句級別的readview。讀的策略與可重複讀類似。

寫鎖的使用方式。這裡不需要gap lock,只使用記錄鎖。並且事務只持有被update/delete記錄的寫鎖(可重複讀需要保留全部寫鎖直到事務結束,而讀已提交只保留真正更改的)。

repeatable read (可重複讀)

可重複讀是mysql預設的隔離級別,理論上說應該稱作快照(snapshot)隔離級別。讀不加鎖,只有寫才加鎖,讀寫互不阻塞,併發度相對於可序列化級別要高,但會有write skew異常。

事務在開始時建立乙個readview,當讀一條記錄時,會遍歷版本鍊錶,通過當前事務的readview判斷可見性,找到第乙個對當前事務可見的版本,讀這個版本(mvcc)。

對於寫操作,包括locking read(select … for update), update, delete,需要加寫鎖。根據謂詞條件上索引使用情形,鎖定有不同的方式:

有索引:對於索引上有唯一約束且為等值條件的情形,不用gap lock,只鎖定索引記錄。對於其它情形,使用gap lock,相當於謂詞鎖。

沒有索引:由於mysql沒有實現通用的謂詞鎖,這時就相當於鎖全表。

serializable (序列化)

在可序列化級別上,mysql執行s2pl併發控制協議, 一階段申請,一階段釋放。讀寫都要加鎖。

通過回滾,以及恢復,和在併發環境下的隔離做到一致性。

spring的事物管理

事物本身是資料庫中的概念,按理說應該在資料訪問層 dao 絕大多數的情況下,我們是把事物提公升到業務邏輯層 01,使用spring的事務 工廠來管理事務 02,使用spring的註解來管理事務 常用 03,使用aspectj的aop配置來管理裡事務 需要掌握的兩個屬性名 isolation 事務隔離...

關於mysql裡面的事物 mysql 事物

mysql之事物詳解 一 事務定義 事務 乙個最小的不可再分的工作單元 通常乙個事務對應乙個完整的業務 例如銀行賬戶轉賬業務,該業務就是乙個最小的工作單元 乙個完整的業務需要批量的dml insert update delete 語句共同聯合完成 事務只和dml語句有關,或者說dml語句才有事務。這...

EJB 事物管理

ejb 事務管理分為兩種,一種由容器管理,用 transactionattribute宣告事務的型別。另外一種由bean管理,由 transactionmanagement宣告,由自己手動開啟,提交,回滾事務。transactionattribute型別 1 required型別 如果存在事務,則傳...