Mysql事務原理與最佳化最佳實踐

圣辉發表於2024-04-28

學習來源-圖靈課堂

https://vip.tulingxueyuan.cn

說到MySQL的innodb的一大特性,就不得不說到事務。今天就學習事務。

事務

事務的定義:邏輯上的一組操作,要麼一起成功,要麼一起失敗,中間絕對不會存在別的狀態。邏輯上的一組操作,就是說這些操作都是有邏輯關係的。

我們通常說的事務是針對修改操作(新增,編輯,刪除),但是查詢操作也是可以加事務的。

事務有四大特性:ACID,就是所謂的原子性,一致性,隔離性,永續性。其中一致性是其它三個特性都滿足之後才能實現的。

  1. 原子性(Atomicity) :當前事務的操作要麼同時成功,要麼同時失敗,從效果上看一體的。原子性由undo log日誌來實現。針對修改操作,undo log中會寫入和其完全相反的一句SQL,便於rollback;rollback和commit是保證原子性的。
  2. 一致性(Consistent) :使用事務的最終目的,由其它3個特性以及業務程式碼正確邏輯來實現。
  3. 隔離性(Isolation) :在事務併發執行時,他們內部的操作不能互相干擾。隔離性由MySQL的各種鎖以及MVCC機制來實現。
  4. 永續性(Durable) :一旦提交了事務,它對資料庫的改變就應該是永久性的。永續性由redo log日誌來實現。

併發事務帶來的問題

  • 更新丟失(Lost Update)或髒寫:當兩個或多個事務選擇同一行資料修改,有可能發生更新丟失問題,即最後的更新覆蓋了由其他事務所做的更新。
  • 髒讀(Dirty Reads):事務A讀取到了事務B已經修改但尚未提交的資料,回滾之後資料無效。
  • 不可重讀(Non-Repeatable Reads):事務A內部的相同查詢語句在不同時刻讀出的結果不一致。主要是針對查詢單條資料,別的事務可能對這行資料進行了修改。
  • 幻讀(Phantom Reads)或者是幻讀:事務A讀取到了事務B提交的新增資料。主要是讀期間別的事務執行了插入操作。每次讀取都能得到新的資料。

事務隔離級別

事務隔離級別是資料庫本身提供的功能。都有其預設值,但是也可以進行修改的。可以根據業務需求去決定是否要修改預設的隔離級別。
隔離級別

髒讀(Dirty Read)

不可重複讀

幻讀(Phantom Read)
讀未提交(Read
uncommitted)
可能   可能  可能
讀已提交(Read
committed)
不可能 可能 可能
可重複讀
(Repeatable read)
不可能 不可能 可能
可序列化
(Serializable)
不可能 不可能 不可能
事務隔離級別越高,其安全性一致性就越好,但是相應的其執行效率就越低。
不同的業務場景針對事務隔離級別有要求,可以針對的進行設定。
MySQL預設的隔離級別是可重複讀;Oracle預設的隔離級別是讀已提交。
用Spring開發程式時,如果不設定隔離級別預設用資料庫設定的隔離級別,如果Spring設定了就用已經設定的隔離級別。

事務隔離級別的具體實現

  • 讀未提交,沒有進行任何額外處理,其資料庫執行效率是最高的,但是其資料庫安全性是最低的, 要在業務側保證事務的執行。
  • 讀已提交,此時是讀的當前,當前讀就是時刻讀取當前的最新已經提交的值。
  • 可重複讀,引入了MVCC和鎖機制去保證。其中MVCC就用到了快照讀,就是讀的歷史版本;鎖機制,提高間隙鎖等。
  • 可序列化,是嚴格的加鎖機制,讀寫互斥,寫寫互斥,讀讀不互斥。是類似Java的悲觀鎖。效率極其低下。

真實的資料只是會維護一份;不同執行緒的查詢是透過整個版本鏈來查的。所有的查詢修改共同構成這條資料的版本鏈。

每次資料的修改,都會有自己的一套版本鏈。查詢的時候,就是透過可見性演算法去定位到自己要查詢的版本。

並不是多個快照,多個日誌,多條真實資料;這樣的話就太佔用空間了。

相關文章