日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL数据库:事务和ACID实现原理

發布時間:2024/9/30 数据库 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL数据库:事务和ACID实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是事務:

????????數據庫的事務是并發控制的基本單位,是指邏輯上的一組操作,要么全部執行,要么全部不執行。

1、事務的特性:

(1)原子性:事務是一個不可分割的工作單元,事務里的操作要么都成功,要么都失敗,如果事務執行失敗,則需要進行回滾。

(2)隔離性:事務的所操作的數據在提交之前,對其他事務的可見程度。

(3)持久性:一旦事務提交,它對數據庫中數據的改變就是永久的。

(4)一致性:事務不能破壞數據的完整性和業務的一致性。例如在轉賬時,不管事務成功還是失敗,雙方錢的總額不變。

二、事務ACID特性的實現原理:

1、原子性:

????????原子性是通過MySQL的回滾日志undo log來實現的:當事務對數據庫進行修改時,InnoDB會生成對應的undo log;如果事務執行失敗或調用了rollback,導致事務需要回滾,便可以利用undo log中的信息將數據回滾到修改之前的樣子。

undo log (回滾日志):是采用段(segment)的方式來記錄的,每個undo操作在記錄的時候占用一個undo log segment。在數據更改操作時,記錄了相對應的undo log的目的在于:

  • 保證數據的原子性,記錄事務發生之前的一個版本,用于回滾;
  • 通過mvcc?+?undo log實現Innodb事務可重復讀和讀已提交隔離級別。

2、隔離性:

隔離性是事務所操作的數據在提交之前,對其他事務的可見程度。

2.1、事務隔離級別:

????????為保證在并發環境下讀取數據的完整性和一致性,數據庫提供了四種事務隔離級別,隔離級別越高,越能保證數據的完整性和一致性,但對高并發性能影響也越大,執行效率越低。(四種隔離級別從上往下依次升高)

讀未提交:允許事務在執行過程中,讀取其他事務尚未提交的數據;

讀已提交:允許事務在執行過程中讀取其他事務已經提交的數據;

可重復讀(默認級別):在同一個事務內,任意時刻的查詢結果都是一致的;

讀序列化:所有事務逐個依次執行,每次讀都需要獲取表級共享鎖,讀寫會相互阻塞。

2.2、如果不考慮事務的隔離性,在事務并發的環境下,可能存在問題有

(1)更新丟失:兩個或多個事務操作相同的數據,然后基于選定的值更新該行時,由于每個事務都不知道其他事務的存在,就會發生丟失更新問題:最后的更新覆蓋了其他事務所做的更新。

(2)臟讀:指事務A正在訪問數據,并且對數據進行了修改(事務未提交),這時,事務B也使用這個數據,后來事務A撤銷回滾,并把修改后的數據恢復原值,B讀到的數據就與數據庫中的數據不一致,即B讀到的數據是臟數據。

(3)不可重復讀:在一個事務內,多次讀取同一個數據,但是由于另一個事務在此期間對這個數據做了修改并提交,導致前后讀取到的數據不一致;

(4)幻讀:在一個事務中,先后兩次進行讀取相同的數據(一般是范圍查詢),但由于另一個事務新增或者刪除了數據,導致前后兩次結果不一致。

① 不可重復讀和幻讀的區別:

不可重復讀側重于讀取到其他事務修改的數據,幻讀側重于讀取到其他事務新增或者刪除的數據。

② 可以采用鎖機制來解決不可重復讀和幻讀:

對于不可重復讀,只需對操作的數據添加行級鎖,防止操作的數據發生變化;而對于幻讀,需要添加表級鎖,將整張表鎖定,防止新增或者刪除數據。

不同的事務隔離級別,在并發環境會存在不同的并發問題:

√:可能出現的情況?

×:不會出現該情況

臟讀

不可重復讀

幻讀

讀序列化

×

×

×

可重復讀

×

×

讀已提交

×

讀未提交

2.3、事務隔離性的實現原理:

????????為了實現事務隔離,數據庫延伸出了數據庫鎖,其中Innodb事務的隔離級別是由鎖機制和MVVC(多版本并發控制)實現的:

2.3.1、Mysql鎖機制:

????????MySQL鎖機制的基本工作原理就是:事務在修改數據庫之前,需要先獲得相應的鎖,獲得鎖的事務才可以修改數據;在該事務操作期間,這部分的數據是鎖定,其他事務如果需要修改數據,需要等待當前事務提交或回滾后釋放鎖。(鎖機制的更多說明可以參考另一篇博客:MySQL數據庫:鎖機制)

????????通過對InnoDB不同鎖類型的特性分析,可以利用鎖解決臟讀、不可重復讀、幻讀:

  • 排它鎖解決臟讀:在讀已提交的隔離級別下,事務A只有在對數據修改時才加排它鎖,但直到事務?commit 時才釋放鎖。因此,同時進行的事務B希望讀取同一行數據時,會被事務A的排它鎖堵塞,所以解決了臟讀的問題

  • 共享鎖解決不可重復讀:在可重復讀的隔離級別下,除了執行讀已提交的排它鎖方式,還會在讀取一行數據時,為這行數據添加共享鎖直至事務 commit。例如,事務A讀取ID=1這一行數據,然后為ID=1添加共享鎖,事務B同時希望update ID=1,此時獲取寫鎖失敗,因此在事務A執行完之前,沒有其他任何事務可以對ID=1這一行做修改,因此解決了重復讀的問題

  • 臨鍵鎖解決幻讀

????????雖然共享鎖和排它鎖解決了事務隔離的并發問題,但鎖會導致大量的堵塞,性能下降。某些時候會造成死鎖,為了解決死鎖,還要添加死鎖探測機制,性能進一步下降,因此需要更高效的方式實現事務的隔離級別,也就是 MVCC 多版本并發控制。

2.3.2、Multiversion concurrency control?(MVCC?多版本并發控制):

????????InnoDB 的?MVCC 的實現思路是:對每一行數據用 undo log 記錄多個版本,每個版本的數據可能都不相同,然后根據 事務ID 去尋找適合它的版本數據,從而實現不同事務之間的隔離性。MVCC 具體實現實現方式是在每行記錄后面保存兩個隱藏的列:

  • DB_TRX_ID:標識當前數據屬于哪個事務,每次提交事務,事務ID會自增,事務開始時會把該事務ID放到當前事務影響的行事務ID字段中,
  • DB_ROLL_PTR:指向該行數據 undo log 的指針,undo log 日志文件保存了該行記錄的所有版本數據,并在日志中通過鏈表形式組織

????????通過 MVCC,數據庫可以使得事務的讀取不需要很多讀鎖,提升了數據庫的性能。當一個事務完成時,數據庫會刪除關于這條事務所有的 undo log,若未完成事務數據庫崩潰則根據 undo log回滾,實現原子性。

????????MVCC只在 可重復度 和 讀已提交 兩個隔離級別下才會工作,其中,MVCC實質就是通過保存數據在某個時間點的快照來實現的。?

  • 讀已提交:事務A執行每一條語句時,生成一份活躍事務表,根據這份表去獲取數據,因此不會獲取到臟數據(未提交事務引起的),但會有重復讀問題(因為可以讀取到commit 的事務數據)
  • 可重復讀:事務A只有在事務開始時才生成一份活躍事務表,因此不會讀取到事務A執行中 commit 的其它事務引起的數據變更,也就不存在重復讀問題。

????????在并發訪問數據庫時,對正在事務中的數據做MVCC多版本的管理,以避免寫操作阻塞讀操作,并且可以通過比較版本解決快照讀方式的幻讀問題,但對于當前讀的幻讀,MVCC并不能解決,需要通過臨鍵鎖來解決。

  • 快照讀:Innodb快照讀,數據的讀取將由 cache(原本數據) + undo(事務修改前的數據) 兩部分組成
  • 當前讀:SQL讀取的數據是最新版本。通過鎖機制來保證讀取的數據無法通過其他事務進行修改

在可重復讀的隔離級別下,MVCC具體操作:

(1)SELECT操作:InnoDB遵循以下兩個規則:

  • 只查找數據行的事務ID小于或等于當前事務ID的版本,這樣可以確保事務讀取的行,要么是在事務開始前已經存在的,要么是事務自身插入或者修改過的記錄。
  • 行的刪除版本要未被定義,讀取到事務開始之前狀態的版本,這可以確保事務讀取到的行,在事務開始之前未被刪除。只有同時滿足的兩者的記錄,才能返回作為查詢結果。

(2)INSERT:InnoDB為新插入的每一行保存當前事務編號作為行版本號。

(3)DELETE:InnoDB為刪除的每一行保存當前事務編號作為行刪除標識。

(4)UPDATE:InnoDB為插入一行新記錄,保存當前事務編號作為行版本號,同時保存當前事務編號到原來的行作為行刪除標識。

保存這兩個額外系統版本號,使大多數讀操作都可以不用加鎖。這樣設計使得讀數據操作很簡單,性能很好,并且也能保證只會讀取到符合標準的行,不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。

3、持久性:

????????持久性的實現關鍵在于redo log日志,在執行SQL時會保存已執行的SQL語句到一個指定的Log文件,當執行recovery時重新執行redo log記錄的SQL操作。

3.1、redo log日志:

????????當向數據庫寫入數據時,執行過程會首先寫入Buffer Pool,Buffer Pool中修改的數據會定期刷新到磁盤中(這一過程叫做刷盤),這整一過程稱為redo log。redo log 分為:

  • Buffer Pool內存中的日志緩沖(redo log buffer),該部分日志是易失性的;
  • 磁盤上的重做日志文件(redo log file),該部分日志是持久的。

????????Buffer Pool的使用可以大大提高了讀寫數據的效率,但是也帶了新的問題:如果MySQL宕機,而此時Buffer Pool中修改的數據在內存還沒有刷新到磁盤,就會導致數據的丟失,事務的持久性無法保證。

????????為了確保事務的持久性,在當事務提交時,會調用fsync接口對redo log進行刷盤, (即redo log buffer寫日志到磁盤的redo log file中 ),刷新頻率由 innodb_flush_log_at_trx_commit變量來控制的:

  • 0:?每秒刷新緩沖池中的數據寫入到磁盤中的,當系統崩潰,會丟失1秒鐘的數據 ;
  • 1: 事務每次提交的時候,就把緩沖池中的數據刷新到磁盤中;
  • 2:提交事務的時候,把緩沖池中的數據寫入磁盤文件對應的 os cache 緩存里去,而不是直接進入磁盤文件。可能 1 秒后才會把 os cache 里的數據寫入到磁盤文件里去。

4、一致性:

一致性指的是事務不能破壞數據的完整性和業務的一致性 :

  • 數據的完整性: 實體完整性、列完整性(如字段的類型、大小、長度要符合要求)、外鍵約束等

  • 業務的一致性:例如在銀行轉賬時,不管事務成功還是失敗,雙方錢的總額不變。

那是如何保證數據一致性的?其實數據一致性是通過事務的原子性、持久性和隔離性來保證的:

  • 原子性:語句要么全執行,要么全不執行,是事務最核心的特性,事務本身就是以原子性來定義的;主要基于undo log實現
  • 持久性:保證事務提交后不會因為宕機等原因導致數據丟失;主要基于redo log實現
  • 隔離性:保證事務執行盡可能不受其他事務影響;InnoDB默認的隔離級別是RR,RR的實現主要基于鎖機制(包含next-key lock)、MVCC(包括數據的隱藏列、基于undo log的版本鏈、ReadView)

總結

以上是生活随笔為你收集整理的MySQL数据库:事务和ACID实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。