深入解析Mysql中事務的四大隔離級別及其所解決的讀現象

来源:https://www.cnblogs.com/kyoner/archive/2019/08/16/11366805.html
-Advertisement-
Play Games

本文詳細介紹四種事務隔離級別,並通過舉例的方式說明不同的級別能解決什麼樣的讀現象。並且介紹了在關係型資料庫中不同的隔離級別的實現原理。 在DBMS中,事務保證了一個操作序列可以全部都執行或者全部都不執行(原子性),從一個狀態轉變到另外一個狀態(一致性)。由於事務滿足久性。所以一旦事務被提交之後,數據 ...


本文詳細介紹四種事務隔離級別,並通過舉例的方式說明不同的級別能解決什麼樣的讀現象。並且介紹了在關係型資料庫中不同的隔離級別的實現原理。

在DBMS中,事務保證了一個操作序列可以全部都執行或者全部都不執行(原子性),從一個狀態轉變到另外一個狀態(一致性)。由於事務滿足久性。所以一旦事務被提交之後,數據就能夠被持久化下來,又因為事務是滿足隔離性的,所以,當多個事務同時處理同一個數據的時候,多個事務直接是互不影響的,所以,在多個事務併發操作的過程中,如果控制不好隔離級別,就有可能產生臟讀、不可重覆讀、丟失修改、或者幻讀等讀現象

在資料庫事務的ACID四個屬性中,隔離性是一個最常放鬆的一個。可以在數據操作過程中利用資料庫的鎖機制或者多版本併發控制機制獲取更高的隔離等級。但是,隨著資料庫隔離級別的提高,數據的併發能力也會有所下降。所以,如何在併發性和隔離性之間做一個很好的權衡就成了一個至關重要的問題。

在軟體開發中,幾乎每類這樣的問題都會有多種最佳實踐來供我們參考,很多DBMS定義了多個不同的“事務隔離等級”來控制鎖的程度和併發能力。

ANSI/ISO SQL定義的標準隔離級別有四種,從高到底依次為:可序列化(Serializable)、可重覆讀(Repeatable reads)、提交讀(Read committed)、未提交讀(Read uncommitted)。

下麵將依次介紹這四種事務隔離級別的概念、用法以及解決了哪些問題(讀現象)

未提交讀(Read uncommitted)

未提交讀(READ UNCOMMITTED)是最低的隔離級別。通過名字我們就可以知道,在這種事務隔離級別下,一個事務可以讀到另外一個事務未提交的數據。

未提交讀的資料庫鎖情況(實現原理)

事務在讀數據的時候並未對數據加鎖。事務在修改數據的時候只對數據增加行級共用鎖

現象:

事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新(因為事務一併未對數據增加任何鎖)

當事務2對該記錄進行更新時,事務1再次讀取該記錄,能讀到事務2對該記錄的修改版本(因為事務二只增加了共用讀鎖,事務一可以再增加共用讀鎖讀取數據),即使該修改尚未被提交。

事務1更新某行記錄時,事務2不能對這行記錄做更新,直到事務1結束。(因為事務一對數據增加了共用讀鎖,事務二不能增加排他寫鎖進行數據的修改)

舉例

事務一 事務二
/* Query 1 */ SELECT age FROM users WHERE id = 1; /* will read 20 */
/* Query 2 */ UPDATE users SET age = 21 WHERE id = 1; /* No commit here */
/* Query 1 */ SELECT age FROM users WHERE id = 1; /* will read 21 */
ROLLBACK; /* lock-based DIRTY READ */

下麵還是借用我在資料庫的讀現象淺析一文中舉的例子來說明在未提交讀的隔離級別中兩個事務之間的隔離情況。

事務一共查詢了兩次,在兩次查詢的過程中,事務二對數據進行了修改,並未提交(commit)。但是事務一的第二次查詢查到了事務二的修改結果。在資料庫的讀現象淺析中我們介紹過,這種現象我們稱之為臟讀。

所以,未提交讀會導致臟讀

提交讀(Read committed)

提交讀(READ COMMITTED)也可以翻譯成讀已提交,通過名字也可以分析出,在一個事務修改數據過程中,如果事務還沒提交,其他事務不能讀該數據。

提交讀的資料庫鎖情況(實現原理)

事務對當前被讀取的數據加行級共用鎖(當讀到時才加鎖)一旦讀完該行,立即釋放該行級共用鎖;

事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加行級排他鎖,直到事務結束才釋放

現象:

事務1在讀取某行記錄的整個過程中,事務2都可以對該行記錄進行讀取(因為事務一對該行記錄增加行級共用鎖的情況下,事務二同樣可以對該數據增加共用鎖來讀數據。)。

事務1讀取某行的一瞬間,事務2不能修改該行數據,但是,只要事務1讀取完改行數據,事務2就可以對該行數據進行修改。(事務一在讀取的一瞬間會對數據增加行級共用鎖,任何其他事務都不能對該行數據增加排他鎖。但是事務一隻要讀完該行數據,就會釋放行級共用鎖,一旦鎖釋放,事務二就可以對數據增加排他鎖並修改數據)

事務2更新某行記錄時,事務1不能對這行記錄做讀取或更新,直到事務2結束。(事務2在更新數據的時候,會對該行數據增加排他鎖,直到事務結束才會釋放鎖,所以,在事務2沒有提交之前,事務1都不能對數據增加共用鎖進行數據的讀取。所以,提交讀可以解決臟讀的現象

舉例

事務一 事務二
/* Query 1 */ SELECT * FROM users WHERE id = 1;
/* Query 2 */ UPDATE users SET age = 21 WHERE id = 1; COMMIT; /* in multiversion concurrency control, or lock-based READ COMMITTED */
/* Query 1 */ SELECT * FROM users WHERE id = 1; COMMIT; /*lock-based REPEATABLE READ */

在提交讀隔離級別中,在事務二提交之前,事務一不能讀取數據。只有在事務二提交之後,事務一才能讀數據。

但是從上面的例子中我們也看到,事務一在一次事務中兩次讀取的結果並不一致,所以提交讀不能解決不可重覆讀的讀現象。

簡而言之,提交讀這種隔離級別保證了讀到的任何數據都是提交的數據,避免了臟讀(dirty reads)。但是不保證事務重新讀的時候能讀到相同的數據,因為在每次數據讀完之後其他事務可以修改剛纔讀到的數據。

可重覆讀(Repeatable reads)

可重覆讀(REPEATABLE READS),由於提交讀隔離級別會產生不可重覆讀的讀現象。所以,比提交讀更高一個級別的隔離級別就可以解決不可重覆讀的問題。這種隔離級別就叫可重覆讀。

可重覆讀的資料庫鎖情況

事務在讀取某數據的瞬間(就是開始讀取的瞬間),必須先對其加行級共用鎖,直到事務結束才釋放;

事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加行級排他鎖,直到事務結束才釋放。

現象

事務1在讀取某行記錄的整個過程中,事務2都可以對該行記錄進行讀取(因為事務一對該行記錄增加行級共用鎖的情況下,事務二同樣可以對該數據增加共用鎖來讀數據。)。

事務1在讀取某行記錄的整個過程中,事務2都不能修改該行數據(事務1在讀取的整個過程會對數據增加共用鎖,直到事務提交才會釋放鎖,所以整個過程中,任何其他事務都不能對該行數據增加排他鎖。所以,可重覆讀能夠解決不可重覆讀的讀現象

事務1更新某行記錄時,事務2不能對這行記錄做讀取、更新,直到事務1結束。(事務1在更新數據的時候,會對該行數據增加排他鎖,知道事務結束才會釋放鎖,所以,在事務2沒有提交之前,事務一都能不對數據增加共用鎖進行數據的讀取。所以,提交讀可以解決臟讀的現象

舉例

事務一 事務二
/* Query 1 */ SELECT * FROM users WHERE id = 1; COMMIT;
/* Query 2 */ UPDATE users SET age = 21 WHERE id = 1; COMMIT; /* in multiversion concurrency control, or lock-based READ COMMITTED */

在上面的例子中,只有在事務一提交之後,事務二才能更改該行數據。所以,只要在事務一從開始到結束的這段時間內,無論他讀取該行數據多少次,結果都是一樣的。

從上面的例子中我們可以得到結論:可重覆讀隔離級別可以解決不可重覆讀的讀現象。但是可重覆讀這種隔離級別中,還有另外一種讀現象他解決不了,那就是幻讀。看下麵的例子:

事務一 事務二
/* Query 1 */ SELECT * FROM users WHERE age BETWEEN 10 AND 30;
/* Query 2 */ INSERT INTO users VALUES ( 3, 'Bob', 27 ); COMMIT;
/* Query 1 */ SELECT * FROM users WHERE age BETWEEN 10 AND 30;

上面的兩個事務執行情況及現象如下:

1.事務一的第一次查詢條件是age BETWEEN 10 AND 30;如果這是有十條記錄符合條件。這時,他會給符合條件的這十條記錄增加行級共用鎖。任何其他事務無法更改這十條記錄。

2.事務二執行一條sql語句,語句的內容是向表中插入一條數據。因為此時沒有任何事務對錶增加表級鎖,所以,該操作可以順利執行。

3.事務一再次執行SELECT * FROM users WHERE age BETWEEN 10 AND 30;時,結果返回的記錄變成了十一條,比剛剛增加了一條,增加的這條正是事務二剛剛插入的那條。

所以,事務一的兩次範圍查詢結果並不相同。這也就是我們提到的幻讀

可序列化(Serializable)

可序列化(Serializable)是最高的隔離級別,前面提到的所有的隔離級別都無法解決的幻讀,在可序列化的隔離級別中可以解決。

我們說過,產生幻讀的原因是事務一在進行範圍查詢的時候沒有增加範圍鎖(range-locks:給SELECT 的查詢中使用一個“WHERE”子句描述範圍加鎖),所以導致幻讀。

可序列化的資料庫鎖情況(實現原理)

事務在讀取數據時,必須先對其加表級共用鎖 ,直到事務結束才釋放;

事務在更新數據時,必須先對其加表級排他鎖 ,直到事務結束才釋放。

現象

事務1正在讀取A表中的記錄時,則事務2也能讀取A表,但不能對A表做更新、新增、刪除,直到事務1結束。(因為事務一對錶增加了表級共用鎖,其他事務只能增加共用鎖讀取數據,不能進行其他任何操作)

事務1正在更新A表中的記錄時,則事務2不能讀取A表的任意記錄,更不可能對A表做更新、新增、刪除,直到事務1結束。(事務一對錶增加了表級排他鎖,其他事務不能對錶增加共用鎖或排他鎖,也就無法進行任何操作)

雖然可序列化解決了臟讀、不可重覆讀、幻讀等讀現象。但是序列化事務會產生以下效果:

1.無法讀取其它事務已修改但未提交的記錄。

2.在當前事務完成之前,其它事務不能修改目前事務已讀取的記錄。

3.在當前事務完成之前,其它事務所插入的新記錄,其索引鍵值不能在當前事務的任何語句所讀取的索引鍵範圍中。


四種事務隔離級別從隔離程度上越來越高,但同時在併發性上也就越來越低。之所以有這麼幾種隔離級別,就是為了方便開發人員在開發過程中根據業務需要選擇最合適的隔離級別。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 把對應的不同文件內的代碼段,合併到一起,成為最後的可執行文件 鏈接的方式,讓我們在寫代碼的時候做到了“復用”。 同樣的功能代碼只要寫一次,然後提供給很多不同的程式進行鏈接就行了。 “鏈接”其實有點兒像我們日常生活中的 標準化、模塊化 生產。 有一個可以生產標準螺帽的生產線,就可生產很多不同的螺帽。 ...
  • 一、索引創建 1. 非結構化創建 2. 結構化創建 二、插入 1. 指定文檔ID插入 2. 自動產生文檔ID插入 三、修改 1. 直接修改文檔 2. 腳本修改文檔 四、刪除 1. 刪除文檔 2. 刪除索引 五、查詢 1. 簡單查詢 2. 條件查詢 3. 聚合查詢 ...
  • 參考:https://ci.apache.org/projects/flink/flink-docs-release-1.8/dev/api_concepts.html DataSet and DataStream Flink具有特殊類DataSet和DataStream來表示程式中的數據。 你可以 ...
  • 比爾·蓋茨在上世紀80年代說的“640K ought to be enough for anyone” 也就是“640K記憶體對哪個人來說都夠用了” 那個年代,微軟開發的還是DOS操作系統,程式員們還在絞盡腦汁,想要用好這極為有限的640K記憶體 而現在,我手頭的Mac Book Pro已經是16G記憶體 ...
  • 本機到本機的配置: 源端 10.1.83.144:1521/SIBP_GSDY HNSIB_GSDY目標端 10.1.83.144:1521/SIBP_GS HNSIB_GS進程名規劃 :OBB05 源端抽取進程及文件首碼:BG01_DY DY 目標端恢復進程:OBR01 //環境變數設置#for ...
  • 首先在edelivery中下載Oracle Linux 8.0然後就預設安裝系統環境準備工具目前不支持OL8,所以需要手動安裝,首先設置內核參數,在/etc/sysctl.conf追加[root@localhost ~]# cat /etc/sysctl.conf |grep -v ^#|grep ... ...
  • MySQL是一個小巧玲瓏但功能強大的資料庫,目前十分流行。但是官網給出的安裝包有兩種格式,一個是msi格式,一個是zip格式的。很多人下了zip格式的解壓發現沒有setup.exe,面對一堆文件一頭霧水,不知如何安裝。下麵筆者將介紹如何解決此情況下安裝過程中的各種問題 MySQL是一個小巧玲瓏但功能 ...
  • [學習筆記] JDBC是什麼? JDBC即(java database connectivity數據連接)。JDBC是Sun公司編的一堆類和方法,都封裝在java.sql包中。你可以利用這堆類和方法來把你的程式和資料庫連通。 JDBC的優點:跨資料庫性 通過使用JDBC,開發人員可以將SQL語句傳送 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...