MySQL 事務 | ACID、四種隔離級別、并發帶來的隔離問題、事務的使用與實現

文章目錄

  • 事務
  • ACID
  • 并發帶來的隔離問題
    • 幻讀(虛讀)
    • 不可重復讀
    • 臟讀
    • 丟失更新
  • 隔離級別
    • Read Uncommitted (讀未提交)
    • Read Committed (讀已提交)
    • Repeatable Read (可重復讀)
    • Serializable (可串行化)
  • 事務的使用
  • 事務的實現
    • Redo
    • undo


事務

事務指邏輯上的一組操作。

我們在 MySQL 存儲引擎 | MyISAM 與 InnoDB 中提到,MyISAM引擎 并不支持事務,所以本文內容主要與 InnoDB引擎 相關。

這篇博客寫事務也寫得很好:我以為我對Mysql事務很熟,直到我遇到了阿里面試官


ACID

談到事務,那肯定少不了ACID的特性,ACID是以下幾個單詞的縮寫:

原子性(atomicity):

事務是一個不可分割的工作單位,對數據的修改要么全部執行成功,要么全部失敗。

舉個例子:事務A中要進行轉賬,那么轉出的賬號要扣錢,轉入的賬號要加錢,這兩個操作都必須同時執行成功,從而確保數據的一致性。

一致性(consistency):

事務操作前與操作后數據庫的狀態始終一致。

如何理解呢?就好比我們此時有用戶A和用戶B,他們的余額分別為300元和700元,此時兩人總金額為1000元。此時若是用戶B向用戶A轉賬200元,則兩者的此時都有500元,總金額還是1000元。

也就是說,無論我們兩個怎么轉賬,總金額它只會是1000,既不會多,也不會少。這就是事務操作前后的狀態始終一致。倘若錢多了或者少了,都代表著事務將數據庫從一種狀態變為了另外一種狀態,此時就不再符合一致性了。

隔離性(isolation):

隔離性指的是每個讀寫事務的對象之間相互隔離,即該事務提交前對其他事務都不可見。

持久性(durability):

持久性指的是事務一旦提交,這個事務的狀態會被持久化到數據庫中。 即使發生了服務器宕機的事故,數據庫也能成功的將數據給恢復。

但是需要注意的是,只能保證數據庫本身發生的問題后可以恢復,但并不是事務提交后所有變化都是永久的,倘若是由于外部原因如:RAID卡損壞、天災人禍導致數據庫發生問題,那么即使事務提交了,也可能會丟失。

基于上述原因,持久性只能保證事務系統的高可靠性,而無法保證其高可用性。

總結:

原子性、隔離性、持久性都是為了保障一致性而存在的,一致性也是最終的目的。


并發帶來的隔離問題

幻讀(虛讀)

幻讀指 在同一事務中,用同樣的操作讀取兩次,得到的記錄數卻不一樣(針對 insert 操作)。 舉個例子:

  • 第一個事務對表中的所有數據行進行修改;
  • 同時,第二個事務向表中插入了一行。這樣也就導致了操作第一個事務的用戶發現表中還有沒修改的數據行,像發生了幻覺一樣。

在這里插入圖片描述
明明在 會話A 的第一次查詢中,大于 2 的數只有行只有一行,而由于 會話B 插入了新行后,對于 會話A 而言就憑空多出來了一行,像出現了幻覺一樣。


不可重復讀

不可重復讀指的是在一個事務中多次讀取同一行數據,但是多次讀取的數據卻不一樣(針對 update 操作)。導致這一問題的主要原因就是一個事務讀取到了其他事務已提交的數據

例如:

  1. 賬戶1中有300元,賬戶2中有500元
  2. 事務A讀取賬戶B的內容,里面顯示有500元
  3. 事務B將賬戶1的300元全部轉給賬戶2,并提交事務
  4. 事務A再次讀取賬戶B,此時里面有800元。

由于其他事務的干擾,對于事務A來說,兩次讀取的金額都不一樣。

因為不可重復讀讀到的是已經提交的數據,由于其本身并不會帶來很大的問題,所以大部分數據庫廠商都會允許這種情況的發生。

在這里插入圖片描述


臟讀

臟讀即一個事務讀取到了另外一個事務中未提交的數據,也就是可能因為其他事務對數據進行修改或者回滾導致的問題。

在這里插入圖片描述
會話B 在第一次查看時表中只有一條數據,但是在第五階段中 會話A 向表中插入了另一條數據(但還未commit【提交】),這就導致了 會話B 在讀取的時候得到的結果就不再一樣,因為它讀取到了臟數據。

臟讀的現象并不會經常發生,因為臟讀發生的條件是需要事務的隔離級別為 READ UNCOMMITTED(讀未提交),而大部分數據庫的默認隔離級別都為 READ COMMITTED(讀已提交)


丟失更新

丟失更新就是一個事務的更新操作會被另外一個事務的更新操作所覆蓋,從而導致數據的不一致。例如以下案例:

  1. 事務A行記錄r 更新為 1,但是 事務A 并未提交;
  2. 同時,事務B行記錄r 更新為 2事務B 也未提交;
  3. 事務A提交;
  4. 事務B提交。

此時由于 BA 的修改覆蓋,導致 A 雖然提交,但是更新卻丟失了,只剩下了 B 的更新。

但是在當前數據庫的任何隔離級別下,都不會導致理論意義上的丟失更新問題,即使是隔離級別最低的 Read Uncommitted,也由于加鎖保護,所以 事務B 的修改操作會被阻塞,直到 事務A 提交。


隔離級別

為了解決上述問題,MySQL中實現了以下四種隔離級別,隔離級別由低到高依次是:

  • 讀未提交(READ UNCOMMITTED)
  • 讀已提交 (READ COMMITTED)
  • 可重復讀 (REPEATABLE READ)
  • 串行化 (SERIALIZABLE)

隔離級別越高,事務請求的鎖也就越多,保持鎖的時間也就越長。所以隔離性越強,并發的效率也就越低。


Read Uncommitted (讀未提交)

在該隔離級別下,所有事務都可以看到其他未提交事務的執行結果,容易產生臟讀問題。

在該級別下,雖然并發的效率最高,但是安全性完全沒有得到保護,所以很少用于實際應用。


Read Committed (讀已提交)

該隔離級別是大部分數據庫默認的隔離級別,如 OracleSQL Server 等。該隔離級別下,一個事務只能看見提交了的事務所做的改變,容易產生不可重復讀的問題。

雖然它還有,但不可重復讀本身并不是一個大問題,所以為了兼顧到性能,大部分數據庫都會容許這種問題的產生。


Repeatable Read (可重復讀)

這是 MySQLInnoDB 默認的隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行,容易產生幻讀的問題。

InnoDB 可以借助 MVCC 中的 Next-Key Locking 的加鎖方式來解決這個問題,詳見本文。


Serializable (可串行化)

這是最高的隔離級別,通過強制事務進行排序,使事務之間不可能互相沖突,從而解決了其他隔離級別無法解決的幻讀問題

由于其在每個讀的數據行上加了共享鎖,所以在該隔離級別下可能會導致大量的超時現象以及鎖競爭


這四種隔離級別分別可能發生的問題如下圖所示:
在這里插入圖片描述


事務的使用

開啟事務

START TRANSACTION
或者
BEGIN
(由于MySQL的數據分析器會自動將BEGIN識別為BEGIN...END,所以在存儲過程中只能使用START TRANSACTION來開啟事務)

提交事務

COMMIT

回滾事務

//回滾整個事務
ROLLBACK//回滾至某個保存點
ROLLBACK TO SAVEPOINT [保存點ID]

設置保存點

SAVEPOINT 保存點ID

刪除保存點

RELEASE SAVEPOINT 保存點ID

查看隔離級別

// 可以看到 MySQL 的 InnoDB存儲引擎 的默認隔離級別為可重復讀
mysql> SELECT @@TRANSACTION_ISOLATION;
+-------------------------+
| @@TRANSACTION_ISOLATION |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

設置隔離級別

SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
// GLOBAL 也可以換成 SESSION,前者表示全局的,后者表示當前會話,也就是當前窗口有效。

PS:當設置完隔離級別后對于之前打開的會話,是無效的,要重新打開一個窗口設置隔離級別才生效。
在這里插入圖片描述


事務的實現

  • 事務的持久性主要依靠 Redo log(重做日志)來完成。
  • 原子性、一致性則通過 Undo log(撤銷日志)來完成。
  • 隔離性,則通過鎖來完成。

先簡單說說 Redo 和 Undo :

Redo/Undo機制: 將所有對數據的更新操作都寫到日志中。

  • Redo log 用來記錄某數據塊被修改后的值,可以用來恢復未寫入 data file 的已成功事務更新的數據。Redo 通常是物理日志,記錄的是頁的物理修改操作。
  • Undo log 是用來記錄數據更新前的值,保證數據更新失敗能夠回滾。Undo 是邏輯日志,根據每行記錄進行記錄。

舉個例子:

假如某個時刻數據庫崩潰,當數據庫重啟進行 crash-recovery 時,就會通過 Redo log 將已經提交事務的更改寫到數據文件,而還沒有提交的就通過 Undo log 進行 回滾roll back


Redo

Redo log 由兩部分組成:

  • 一是存在于內存中的 重做日志緩沖(redo log buff),由于存在內存中,所以其具有易失性。
  • 二是 重做日志文件(redo log file),其存在于硬盤中,所以是持久的。

Redo 主要通過 Force Log at Commit機制 來實現事務的持久性。

步驟如下:

在這里插入圖片描述
為了確保日志寫入文件中,每次將日志緩沖寫入日志文件后,都會發起一次 異步操作(fsync)

為什么需要這個異步調用呢?

因為重做日志文件打開時并沒有使用 O_DIRECT 選項,所以重做日志緩沖會先寫入文件系統緩沖,為了保證其能夠成功寫入磁盤,必須發起一次異步調用。由于異步調用的效率取決于磁盤的性能,因此磁盤的性能決定了事務提交的性能,即數據庫性能。


undo

undo 是撤銷日志,其中保留了數據庫各個版本的狀態,我們可以借助 undo 邏輯地將數據庫恢復到原來地樣子。除了進行回滾之外, undo 的另一個作用就是實現 MVCC

首先看看 undo log 的生成流程:
在這里插入圖片描述

在這里插入圖片描述
每當事務發生變更的時候,都會伴隨著 undo log 的產生,并且為了防止其丟失,undo log 會比數據持久化到硬盤上。

由于 undo log 是邏輯日志,所以其中記錄的都是對于數據庫的操作指令。而事務的回滾,其實也就是根據這個操作來進行一個逆向操作。如下面幾種:

  • 當執行一個 insert 指令時,其逆向指令為 delete
  • 當執行一個 delete 指令時,其逆向指令為 insert
  • 當執行一個 update 指令時,其逆向指令為 update

在這里插入圖片描述
原子性就是借助以上機制實現,倘若事務中的某一個步驟未能成功完成,則借助 undo log 中存儲的記錄來回滾到事務的最原始狀態,即一個失敗全體失敗。

而至于一致性,則主要依靠上述的其他三種特性來實現,也就是說一致性是目的,而原子性、隔離性、持久性則是數據庫實現一致性的手段,只有滿足這三個性質,才能夠保證一致性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443744.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443744.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443744.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL 備份與主從復制

文章目錄備份主從復制主從復制的作用備份 根據備份方法的不同,備份可劃分為以下幾種類型: 熱備(Hot Backup) : 熱備指的是在數據庫運行的時候直接備份,并且對正在運行的數據庫毫無影響,這種方法在 MySQL 官方手冊中又…

C++ 流的操作 | 初識IO類、文件流、string流的使用

文章目錄前言IO頭文件iostreamfstreamsstream流的使用不能拷貝或對 IO對象 賦值條件狀態與 iostate 類型輸出緩沖區文件流fstream類型文件模式文件光標函數tellg() / tellp()seekg() / seekp()向文件存儲內容/讀取文件內容string流istringstreamostringstream前言 我們在使用 …

Hibernate 更新部分更改的字段 hibernate update

Hibernate 中如果直接使用 Session.update(Object o);或則是Session.updateOrUpdate(Object o); 會把這個表中的所有字段更新一遍。 如: ExperClass4k e new ExperClass4k(); e.setTime(time); e.setQ_num(q_num); e.setK(k); if (str "finch_fix")…

C++ 類的行為 | 行為像值的類、行為像指針的類、swap函數處理自賦值

文章目錄概念行為像值的類行為像指針的類概念引用計數動態內存實現計數器類的swap概念swap實現自賦值概念 行為像值的類和行為像指針的類這兩種說法其實蠻拗口的,這也算是 《CPrimer》 翻譯的缺點之一吧。。。 其實兩者的意思分別是: 行為像值的類&am…

C++ 右值引用 | 左值、右值、move、移動語義、引用限定符

文章目錄C11為什么引入右值?區分左值引用、右值引用move移動語義移動構造函數移動賦值運算符合成的移動操作小結引用限定符規定this是左值or右值引用限定符與重載C11為什么引入右值? C11引入了一個擴展內存的方法——移動而非拷貝,移動較之拷…

且談關于最近軟件測試的面試

前段時間有新的產品需要招人,安排和參加了好幾次面試,下面就談談具體的面試問題,在面試他人的同時也面試自己。 面試問題是參與面試同事各自設計的,我也不清楚其他同事的題目,就談談自己設計的其中2道題。 過去面試總是…

C++ 多態 | 虛函數、抽象類、虛函數表

文章目錄多態虛函數重寫重定義(參數不同)協變(返回值不同)析構函數重寫(函數名不同)final和override重載、重寫、重定義抽象類多態的原理虛函數常見問題解析虛函數表多態 一種事物,多種形態。換…

C++ 運算符重載(一) | 輸入/輸出,相等/不等,復合賦值,下標,自增/自減,成員訪問運算符

文章目錄輸出運算符<<輸入運算符>>相等/不等運算符復合賦值運算符下標運算符自增/自減運算符成員訪問運算符輸出運算符<< 通常情況下&#xff0c;輸出運算符的第一個形參是一個 非常量ostream對象的引用 。之所以 ostream 是非常量是因為向流寫入內容會改變…

C++ 重載函數調用運算符 | 再探lambda,函數對象,可調用對象

文章目錄重載函數調用運算符lambdalambda等價于函數對象lambda等價于類標準庫函數對象可調用對象與function可調用對象function函數重載與function重載函數調用運算符 函數調用運算符必須是成員函數。 一個類可以定義多個不同版本的調用運算符&#xff0c;互相之間應該在參數數…

C++ 運算符重載(二) | 類型轉換運算符,二義性問題

文章目錄類型轉換運算符概念避免過度使用類型轉換函數解決上述問題的方法轉換為 bool顯式的類型轉換運算符類型轉換二義性重載函數與類型轉換結合導致的二義性重載運算符與類型轉換結合導致的二義性類型轉換運算符 概念 類型轉換運算符&#xff08;conversion operator&#…

Tomcat中JVM內存溢出及合理配置

Tomcat本身不能直接在計算機上運行&#xff0c;需要依賴于硬件基礎之上的操作系統和一個Java虛擬機。Tomcat的內存溢出本質就是JVM內存溢出&#xff0c;所以在本文開始時&#xff0c;應該先對Java JVM有關內存方面的知識進行詳細介紹。 一、Java JVM內存介紹 JVM管理兩種類型的…

俄羅斯農民乘法 | 快速乘

文章目錄概念概念 俄羅斯農民乘法經常被用于兩數相乘取模的場景&#xff0c;如果兩數相乘已經超過數據范圍&#xff0c;但取模后不會超過&#xff0c;我們就可以利用這個方法來拆位取模計算貢獻&#xff0c;保證每次運算都在數據范圍內。 A 和 B 兩數相乘的時候我們如何利用加…

Linux網絡編程 | socket選項設定 及 網絡信息API

文章目錄讀取和設置 socket 選項SO_REUSEADDRSO_RCVBUF 和 SO_SNDBUFSO_RCVLOWAT 和 SO_SNDLOWATSO_LINGER 選項網絡信息APIgethostbyname 和 gethostbyaddrgetservbyname 和 getservbyportgetaddrinfogetnameinfo讀取和設置 socket 選項 正如 fcntl 系統調用是控制文件描述符…

Linux | 高級I/O函數

文章目錄創建文件描述符的函數pipe函數dup函數、dup2函數讀取或寫入數據readv函數、writev函數零拷貝sendfile函數splice函數tee函數進程間通信——共享內存mmap函數 和 munmap函數控制文件描述符fcntl函數創建文件描述符的函數 pipe函數 不再贅述&#xff0c;詳情見我的另一…

分布式理論:CAP、BASE | 分布式存儲與一致性哈希

文章目錄分布式理論CAP定理BASE理論分布式存儲與一致性哈希簡單哈希一致性哈希虛擬節點分布式理論 CAP定理 一致性&#xff08;Consistency&#xff09;&#xff1a; 在分布式系統中的所有數據副本&#xff0c;在同一時刻是否一致&#xff08;所有節點訪問同一份最新的數據副…

Tomcat服務器性能優化

一、概述 本文檔主要介紹了Tomcat的性能調優的原理和方法。可作為公司技術人員為客戶Tomcat系統調優的技術指南&#xff0c;也可以提供給客戶的技術人員作為他們性能調優的指導手冊。 二、調優分類 由于Tomcat的運行依賴于JVM&#xff0c;從虛擬機的角度我們把Tomcat的調整分為…

分布式系統概念 | 分布式事務:2PC、3PC、本地消息表

文章目錄分布式事務2PC&#xff08;二階段提交協議&#xff09;執行流程優缺點3PC&#xff08;三階段提交協議&#xff09;執行流程優缺點本地消息表&#xff08;異步確保&#xff09;分布式事務 分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分…

數據結構算法 | 單調棧

文章目錄算法概述題目下一個更大的元素 I思路代碼下一個更大元素 II思路代碼132 模式思路代碼接雨水思路算法概述 當題目出現 「找到最近一個比其大的元素」 的字眼時&#xff0c;自然會想到 「單調棧」 。——三葉姐 單調棧以嚴格遞增or遞減的規則將無序的數列進行選擇性排序…

最長下降子序列

文章目錄題目解法DP暴搜思路代碼實現貪心二分思路代碼實現題目 給出一組數據 nums&#xff0c;求出其最長下降子序列&#xff08;子序列允許不連續&#xff09;的長度。&#xff08;類似于lc的最長遞增子序列&#xff09; 示例&#xff1a; 輸入&#xff1a; 6 // 數組元素個…

Linux 服務器程序規范、服務器日志、用戶、進程間的關系

文章目錄服務器程序規范日志rsyslogd 守護進程syslog函數openlog函數setlogmask函數closelog函數用戶進程間的關系進程組會話系統資源限制改變工作目錄和根目錄服務器程序后臺化服務器程序規范 Linux 服務器程序一般以后臺進程&#xff08;守護進程[daemon]&#xff09;形式運…