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

歡迎訪問 生活随笔!

生活随笔

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

数据库

MySQL事务——万字详解

發布時間:2024/3/12 数据库 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL事务——万字详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

前言

一.事務的概念

? ? ? ? 1.1 什么是事務

? ? ? ? 1.2 事務的屬性

? ? ? ? 1.3 事務的版本支持

? ? ? ? ?1.4 事務提交方式

? ? ? ? ?1.5 事務的常見操作

? ? ? ? 1.5.1 準備階段:

? ? ? ? ?1.5.2 手動演示回滾操作

? ? ? ? ? 1.5.3 簡單證明原子性

? ? ? ? ?1.5.4 簡單證明持久性? ? ?

? ? ? ? 1.5.5 begin開啟的事務不會受MySQL事務提交方式的影響

? ? ? ? ?1.5.6 MySQL中SQL與事務的關系

? ? ? ? ?1.5.7 總結

?二.隔離級別

? ? ? ? 2.1 隔離級別介紹

? ? ? ? 2.2 查看和設置隔離性

? ? ? ? 2.3 操作演示

? ? ? ? 2.3.1 讀未提交

? ? ? ? 2.3.2 讀提交

? ? ? ? ?2.3.3 可重復讀

? ? ? ? ?2.3.4 串行化

????????2.3.5 總結

? ? ? ? 2.4 一致性

三.解決并發的原理MVCC

? ? ? ? 3.1 數據庫并發的三種場景

? ? ? ? 3.2 讀和寫

? ? ? ? 3.2.1 三個隱藏字段

? ? ? ? 3.2.2 undo日志

? ? ? ? ?3.2.3 模擬MVCC過程

? ? ? ? 3.2.4 read view

?四.RR和RC的本質區別


前言

? ? ? ? MySQL是一個網絡服務。大多數情況下,會有很多客戶端連接MySQL服務。當多個客戶端訪問同一個表時,可能會出現問題。

? ? ? ? 比如:火車票售票系統,當兩個客戶端同時買票,操作同一張票數表。當客戶端A檢測還有一張票,將票買掉,但是還沒有更新數據庫。于此同時,客戶端B,也在買票,也檢測到還有一張票,客戶端B也將票買了。這樣就導致一張票被賣了兩次。

? ? ? ? 于是MySQL需要對此現象加以控制。這就是事務解決的問題。

要解決上面的問題,至少需要滿足下面的屬性(拿買票的過程舉例):

  • 買票的過程得是原子的
  • 多個客戶端買票,互相之間不能影響
  • 買完票后,數據應該是永久有效的
  • 買票前各個客戶端之間看到的票數要是一樣的;買票后,各個客戶端看到的票數是一樣的

一.事務的概念

? ? ? ? 1.1 什么是事務

? ? ? ? 事務就是一組DML類的SQL語句,這些語句在邏輯上存在相關性,這一組DML語句要么全部成功,要么全部失敗,是一個整體。

? ? ? ? 簡單來說,事務就是要完成一件事,所用到的所有SQL語句(至少一條)。這些語句要么全部執行成功,要么全部執行失敗。即,其中一條執行失敗,就全部執行失敗。數據立馬回滾到執行前的狀態。

? ? ? ? 1.2 事務的屬性

  • 原子性:一個事務中的所有操作,要么全部完成,要么全部不完成。不會結束在中間的某個環節。事務在執行過程中發生錯誤,會被回滾到事務開始前的狀態,就像這個事務沒有發生一樣。
  • 持久性:事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。可以理解成,事務執行完后,就將數據刷新到磁盤中了。但是,這并沒有這么簡單,因為,MySQL是是一個應用程序,數據刷新需要操作系統來做。故MySQL需要先將數據放到內核緩沖區中,再由操作系統將數據刷新到磁盤。
  • 隔離性:數據庫允許多個事務并發運行,并且允許事務同時對數據進行讀,寫和修改。隔離性可以防止多個事務并發執行時由于交叉執行而導致數據不一致的情況。但是,MySQL為了考慮效率,多個事務讀,寫或者修改同一數據時,并不一定是串行運行的。而是分成了不同的級別:讀未提交(read? uncommitted),讀提交(read committed),可重復讀(repeatable read)和串行化(serializable)。
  • 一致性:在事務開始前和事務結束后,數據庫的完整性。并且事務執行后,會完全符合結果。這需要MySQL和用戶共同來保證的。即,MySQL保證了數據保護出錯,用戶需要保存流程正確。

上面四個屬性,可以簡稱ACID。

  • 原子性(Atomicity,又稱不可分割性)
  • 一致性(Consistency)
  • 隔離性(Isolation,又稱獨立性)
  • 持久性(Durability)

事務并不是伴隨著數據庫系統天生就有的,而是為應用層的服務的。

這樣就使得用戶在操作數據庫時不需要考慮數據的安全問題,簡化了編程模型。

? ? ? ? 1.3 事務的版本支持

? ? ? ? 事務是存儲引擎提供的,在MySQL中只有使用了innodb存儲引擎的數據庫或者表才支持事務,MyISAM存儲引擎不支持事務。

查看數據庫存儲引擎:

? ? ? ? ?1.4 事務提交方式

? ? ? ? 事務提交方式有兩種:

  • 手動提交
  • 自動提交

查看事務的提交方式:

?修改事務的提交方式:

? ? ? ? ?1.5 事務的常見操作

? ? ? ? 1.5.1 準備階段:

手動啟動一個事務:

begin/start transaction;--開始一個事務...--對表進行操作commit;--提交事務

?設置隔離級別為讀未提交,后面在隔離性有詳細解釋。

注意:設置完global.transaction_isolation,需要重啟MySQL。

?創建表:

create table if not exists account(id int primary key,name varchar(50) not null default '',blance decimal(10,2) not null default 0.0)ENGINE=InnoDB DEFAULT CHARSET=UTF8;

? ? ? ? ?1.5.2 手動演示回滾操作

? ? ? ? 創建保存點:savepoint? 保存點名;

? ? ? ? 回滾:rollback? 回滾的保存點;

? ? ? ? ? 1.5.3 簡單證明原子性

? ? ? ? 注意:現在的隔離等級是讀為提交。

? ? ? ? 事務沒有執行完發生了錯誤,會回滾到最開始,相當于這個事務沒有發生一樣。

? ? ? ? ?1.5.4 簡單證明持久性? ? ?

? ? ? ? ? 當一個事務完成后,操作完的數據會永久保存,系統是否故障。

? ? ? ? 1.5.5 begin開啟的事務不會受MySQL事務提交方式的影響

? ? ? ? 結論:begin開啟的事務,不受MySQL事務提交方式的影響,必須手動commit提交。

? ? ? ? ?1.5.6 MySQL中SQL與事務的關系

? ? ? ? 結論:在MySQL中沒有手動begin開啟事務,增刪查改都會被MySQL封裝成一個事務,即使只有一條SQL語句。

提交方式為:自動提交。

?提交方式為:手動提交

?正確:

? ? ? ? ?1.5.7 總結

  • 事務可以手動回滾,同時,操作異常會自動回滾。
  • 使用begin/start? transaction開啟的事務,必須通過commit才能提交,才會持久化,與MySQL的提交方式無關。
  • 對于MySQL存儲引擎使用innodb,每一條SQL語句都會默認封裝成事務,提交方式看auto_commit是否開啟。

注意點:

  • 如果沒有設置保存點,也可以回滾,只能回滾到事務最開始。直接使用rollback,前提是事務還沒有提交。
  • 如果一個事務被提交(commit),則不可以回滾。
  • 可以選擇回滾到哪個保存點。
  • Innodb可以支持事務,MyISAM不支持事務。
  • 手動開始事務使用begin,或start? transaction。

?二.隔離級別

? ? ? ? 再次說明,MySQL是一個網絡服務,同一時間可能有很多客戶端連接。那么在多個事務在執行多個SQL時,有可能出現問題,比如:多個事務訪問同一張表,同一行數據時。

? ? ? ? 一個事務的時間段可以分為執行前(該事務還沒有開始),執行中(該事務正在執行),執行后(該事務已經提交)。

? ? ? ? 隔離性:保證了事務執行過程中盡量不受干擾。

? ? ? ? 為了提高效率,執行過程并不是串行化,而是允許事務受到不同程度的干擾,于是就有了一個重要的特征:隔離級別。

? ? ? ? 2.1 隔離級別介紹

? ? ? ? 注意:隔離級別是針對事務之間的。

  • 讀未提交(read uncommitted):在該隔離級別下,所有事務都能看到其它事務沒有提交的執行結果。相當于沒有任何隔離性。在實際生產中不會使用這一隔離級別,因為會有很多并發問題,如臟讀,幻讀,不可重復度等。
  • 讀提交(read committed):事務只能看到其它事務已經提交后執行結果。這種隔離級別是大多數數據庫的默認隔離級別(不是MySQL的),這種隔離級別會引起不可重復讀的問題。
  • 可重復度(repeatable? read):在該隔離級別下,在一時間段同時運行的事務,執行中,看不到其它事務已經提交的執行結果,必須等事務執行完才能看到其它事務提交后執行結果。可能會出現幻讀的問題。這是MySQL的默認隔離級別。
  • 串行化(serialization):強制事務在增刪改同一張表的同一行時排序執行,使之不可能相互沖突。實際,它是在訪問的每一個數據行上加了共享鎖。這是事務最高隔離級別。但是這個的效率很低,可能導致超時和鎖競爭。(這種隔離太極端,生活中基本不使用)

? ? ? ? 隔離基本上都是通過加鎖來實現的,不同隔離級別,鎖的使用是不同的。常見的有,表鎖,行鎖,讀鎖,寫鎖,間隙鎖,Next-key鎖(GAP+行鎖)。

讀提交和可重復讀的區別:

?????????有兩個事務,事務A和事務B。

? ? ? ? 事務A修改數據,提交后(commit)。讀提交,事務B在提交前(commit)可以看到事務A修改后的數據。可重復讀,事務B在提交前(commit)看不到事務A修改后的數據,事務B在提交后,才能看到。

? ? ? ? 2.2 查看和設置隔離性

查看隔離性:

?設置隔離等級:

? ? ? ? 這是設置當前會話或者全局隔離級別的語法。

set? [session |? global]? transaction? isolation? level? ?{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE};

設置當前會話隔離性,另起一個會話,隔離性不會被設置,只影響當前會話。

?設置全局隔離級別,另起一個會話,會被影響。

?會話隔離級別開始啟動時,會和全局隔離級別一樣。

?設置了全局會話隔離級別,當前會話隔離級別并沒有改變,需要重啟MySQL才會改變當前會話隔離級別。

?修改當前會話隔離級別:

  • 直接修改會話隔離級別
  • 修改全局隔離級別,重啟MySQL

? ? ? ? 2.3 操作演示

? ? ? ? 隔離級別時針對事務和事務之間的。

? ? ? ? 2.3.1 讀未提交

? ? ? ? 現象:如果隔離級別為讀未提交,一個事務A增刪改表的內容,未提交事務,在另外一個事務B中可以看到變化的內容。

? ? ? ? 但是,如果事務A沒有提交異常退出了,內容會發生回滾,回滾到事務開始前的內容,原因是事務的原子性。事務A提交了,事務B,提交后也可以看到修改之后的內容,這是應為事務的持久性。

? ? ? ? ?一個事務執行中,讀到了另外一個事務的增刪改,但是沒有commit的數據,這種現象叫做臟讀。

? ? ? ? 2.3.2 讀提交

? ? ? ? 現象:兩個事務,事務A和事務B,隔離等級為讀提交。事務A增刪改表的內容,未提交事務,在事務B中,看不到增刪改的內容。當事務A提交后,事務B中可以看到增刪改的內容。注意事務B沒有提交。

? ? ? ? 問題:此時在事務B中,沒有提交事務。但是同樣的讀取,在同一個事務內,在不同的時間段,讀取到的值不同,這種現在叫做不可重復讀取。

? ? ? ? ?2.3.3 可重復讀

? ? ? ? 現象:兩個事務,事務A和事務B。事務A增刪改表的內容,未提交,事務B看不到修改后的數據;事務A提交后,事務B沒有提交,仍然看不到提交的數據;事務B提交后,由于持久化,可以看到修改后的數據。

? ? ? ? 注意:并不是,同一時段的兩個事務,事務A提交的數據,事務B就一定看不到。這個取決于select 的位置。下面詳細解釋了。

問題:

? ? ? ? 幻讀:在事務只執行中,不同時間段查詢,會查找出來新的記錄。即,事務A插入一條數據,事務B在未提交前,看到了插入的數據。

? ? ? ? 但是,在下面的演示中,在事務A向表中插入數據,事務B中在未提交前沒有看到插入的數據。這是因為MySQL解決了幻讀的問題。

但是,一般的數據庫,在事務未提交前能夠讀到其它數據插入的數據。這是為什么呢?

? ? ? ? 因為隔離性實現是對數據加鎖實現的,而insert數據,插入的數據,在表中并不存在,一般的加鎖無法屏蔽這里問題。

而MySQL是如何解決的呢?

? ? ? ? MySQL用的是Next-Key鎖(GAP+行鎖)解決的。

? ? ? ? ?2.3.4 串行化

? ? ? ? 現象:當前有多個事務時,一個事務要增刪改表的數據,會發生阻塞。當其它數據全部退出,才能正常進行增刪改操作。使得增刪改時,事務之間運行是串行的。效率比較低。

? ? ? ? 但是:如下圖,我們發現,查找,并沒有串行化,有多個事務同時運行時,查找不會被阻塞,串行化。這是因為查詢并不會修改數據。

????????2.3.5 總結

  • 隔離等級越高,安全性越高,并發性越低,因為加鎖。往往要在兩者之間找一個平衡點。
  • 不可重復讀是,同一條件下,事務在執行過程中,不同時間段,讀取的數據不同。
  • 幻讀是,同樣條件下,事務在執行過程中,不同時間段,讀出來,數據量比之前增加了。
  • 臟讀:同樣條件下,事務在執行過程中,讀到了其它事務修改的數據。
  • 事務也有長短的概念,事務之間相互影響,指的是,在事務執行過程中,都沒有提交(commit),影響會比較大。

針對MySQL:

隔離級別臟讀幻讀不可重復讀
讀未提交【Read Uncommitted
讀提交【Read Committed 沒有
可重復讀【Repeatable Read 沒有沒有沒有
串行化【serializable 沒有沒有沒有

注意:

? ? ? ? 當多個事務,同時進行update, insert或者delete時,是會有加鎖現象的。即,會發生阻塞。但是select查詢和增刪改并不沖突,即不會發生阻塞。這是通過讀寫鎖(鎖由行鎖或者表鎖)+MVCC完成的。

? ? ? ? 這里不好演示,直接給了結論。

? ? ? ? 2.4 一致性

  • 事務執行結果,必須使得數據庫從一個一致性的結果,變成另外一個一致性狀態。如果系統運行時發生中斷,某個事務,被迫中斷,而未完成事務對數據的修改,此時數據庫出于一種不一致的狀態。
  • 一致性性就是,在事務開始前,數據是一致的,事務完成后,數據也是一致的。
  • 其實一致性和用戶業務的邏輯性相關,需要MySQL提供技術支持,保證數據不會出錯。還需要用戶業務邏輯上的支持,在MySQL文檔中,一致性,是由用戶來決定的。
  • 技術上,數據庫的原子性,隔離性,持久性保證了一致性。

三.解決并發的原理MVCC

? ? ? ? 對數據庫操作實際上就是對數據庫進行讀和寫的操作,并發就是,多個事務同時對數據庫進行讀和寫操作。而數據庫正是對在效率和安全方面的考慮,解決讀和寫并發的問題。

? ? ? ? 3.1 數據庫并發的三種場景

  • 讀和讀:不會存在任何問題,不需要并發的控制。不會修改數據。
  • 寫和寫:有安全問題,可能會存在數據更新丟失,比如:第一類更新丟失,第二類更新丟失。如事務A更新了數據,事務B回滾導致事務A更新的數據丟失了。需要加鎖,串行運行。
  • 讀和寫:有安全問題,但是為了效率的考慮,不一定加鎖,串行運行。總和考慮效率和安全,所以有了隔離等級,但是,仍然可能有其它問題,臟讀,幻讀,不可重復讀的問題。

讀和讀,寫和寫的問題好處理,但是讀和寫的問題就比較麻煩,下面主要討論如何解決讀和寫并發問題。

? ? ? ? 3.2 讀和寫

? ? ? ? 多版本并發控制(Multiversion concurrency control),簡稱MVCC,是一種解決讀寫沖突的無鎖并發控制。

? ? ? ? 主要是:為事務分配單向增長的事務ID,為每一個修改保存一個版本,版本與事務ID關聯,讀操作只讀改事務開始前的數據的快照(快照,后面有解釋,需要先理解,才能理解)。所以MVCC可以為數據庫解決以下問題:

  • 在并發讀寫數據庫時,可以做到在讀操作時,不用阻塞寫操作,寫操作時也不用阻塞讀操作,因為讀寫的數據不是一個版本。提高了數據庫并發讀寫的性能。
  • 同時還解決了臟讀,幻讀,不可重復讀等事務隔離問題,但不能解決更新丟失問題。

注意:沒有同時啟動的事務,事務的啟動一定會有先后的。所以每個事務的ID一定不同。

想要理解MVCC需要知道三個前提知識:

  • 3個記錄隱藏字段
  • undo日志
  • read view

? ? ? ? 3.2.1 三個隱藏字段

? ? ? ? 當我們在數據庫中創建一個表時,表中的字段不僅會有我們設計的字段,還有有幾個隱藏字段。

這里主要介紹三個:

  • DB_TRX_ID:6字節,保存最近修改(修改/插入)改數據的事務的ID
  • DB_ROLL_PTR:7字節,回滾指針,執行這條記錄的上一個版本。
  • DB_ROW_ID:6字節,隱含的自增ID(隱藏主鍵)。在innodb存儲引擎中,如果數據沒有主鍵,innodb會自動創建一個隱藏主鍵來構建索引。這個隱藏主鍵就是DB_ROW_ID字段記錄的主鍵。

補充:實際上還會有一個刪除flag隱藏字段,即記錄刪除。實際上的刪除一個字段,并不是真正的刪除,而是將flag設置為刪除標記。

演示:

?此時:表的全部信息為:

? ? ? ? ?我們目前并不知道創建該記錄的事務ID,隱式主鍵。默認設置成NULL和1。第一條記錄之前也沒有其它版本,我們設置回滾指針為NULL。

? ? ? ? 3.2.2 undo日志

? ? ? ? undo日志,實際上時MySQL內存緩沖區里的一段空間,即buffer pool中的一段空間,用來保存日志數據,之后再刷新到磁盤中。

? ? ? ? MySQL是一個服務進程,所有操作都需要在內存中完成的。比如:修改數據,先將數據拿到內存中,修改后,再刷新到磁盤中。日志也是一樣,先將日志信息寫到MySQL內部緩沖區中,之后再刷新到磁盤中。

? ? ? ? ?3.2.3 模擬MVCC過程

說明:現在有一個事務,事務ID為10,對student表中的字段做的修改(update),將name從張三,修改成了李四。

過程:

  • 事務10,因為要修改字段,先給記錄加上行鎖。防止有其它記錄同時修改。
  • 修改前,先將當前記錄拷貝到undo log中。
  • 所以現在MySQL中有了兩行相同的記錄。現在修改原始記錄,將名字改為李四。
  • 修改隱藏字段DB_TRX_ID為當前事務10的事務ID,
  • 修改回滾指針DB_ROLL_PTR,里面填入之前拷貝數據的起始地址,從而指向副本數據,表明這是上一個版本。
  • 事務10提交,釋放鎖。

?現在又有一個事務11,對student表進行修改(update):將年齡age由28改成38。

注意:修改,修改的是最新記錄。

  • 事務11,因為要修改,給最新記錄加上行鎖。
  • 修改前,將當前記錄拷貝到undo log中,產生新的副本,我們采用頭插的方式,插入到undo log中。
  • 現在修改原始記錄中的年齡,改成38。
  • 修改隱藏字段DB_TRX_ID為當前事務ID11.
  • 修改回滾指針DB_ROLL_PTR列,保存undo log中新副本的起始地址,從而指向副本記錄,表示上一個版本就是它。
  • 事務11提交,釋放鎖。

?????????于是這樣就是形成了一個基于鏈表記錄的版本鏈。所謂回滾,就是,用歷史數據,覆蓋當前數據。

? ? ? ? 快照:就是undo log中的一個個版本。

????????注意:只有在增刪改動作的時候,才會形成快照。

上面主要講的是修改數據undo log

如果是delete呢?刪除數據了,這個字段就沒有了,如何生成這個字段的快照呢?

? ? ? ? 上面補充的時候說了,在表中還有一個隱藏字段flag,來標記當前字段是否被刪除。所以刪除數據,并不是將數據真正刪除了,而是將flag字段,設置成了刪除標記。所以,刪除字段也可以生成快照,保存在undo log中。

如果是insert呢?插入數據,之前沒有插入數據前面沒有歷史版本,如果要回滾到插入前怎么辦的?

? ? ? ? 起始在MySQL中由記錄數據的log,就像上面一樣。還由基于語句的log,記錄相反的語句。比如:insert一條數據,在log中就會記錄delete的語句。

如果是select呢?

? ? ? ? select不會對數據進行修改,所以不需要為select維護多版本。

select讀取的時候,是讀取的最新數據還是,快照呢?

? ? ? ? select既可以讀取最新數據,也可以讀取快照。

? ? ? ? 當前讀:讀取最新數據。增刪改,都是當前讀,因為需要修改最新的數據。select也可以當前讀,(select? lock? in share? mode,select? for? update),select當前讀時,就需要對數據加鎖,因為增刪改也是當前讀,避免數據錯誤。

? ? ? ? 快照讀:讀取快照。增刪改是當前讀,如果select采用快照讀,這樣不需要加鎖,可以實現讀寫并發,這就是MVCC的意義所在。

那什么決定了select快照讀還是當前讀?

? ? ? ??隔離級別決定的。不同的隔離級別,訪問的數據版本不同。

? ? ? ? 比如:讀提交:每次都可以訪問到修改后的數據,當前讀。讀未提交:訪問不到需改,但是未提交的數據,快照讀。

事務操作哪個版本是在事務啟動時確定的,事務總有先后。事務啟動時,會分配一個事務id,通過對比事務id來確定操作哪個快照。

? ? ? ? 3.2.4 read view

? ? ? ? Read? view是事務進行快照讀操作的時候生產的讀視圖(read view)。決定了這個select可以看到多少版本數據。這個讀視圖中,維護了系統當前活躍事務的id。

? ? ? ? 簡單來說就是,在我們某個事務進行快照讀時,對該記錄創建一個read view,把他當作條件,用來判斷當前事務能夠看到哪個版本的數據。即,可能時最新版本,也可能是undo log中的版本。

在read view中主要由以下四個成員:

  • m_ids:相當于一個數組。記錄read view生成時刻,系統正在執行的事務。
  • up_limit_id:記錄m_ids列表中事務最小的ID。
  • low_limit_id:read view生成時刻,系統尚未分配的下一個事務ID。
  • creator_trx_id:創建read? view的事務id。

? ? ? ? 我們讀取數據版本鏈時,能夠獲得每一個版本對應的事務ID。即:DB_TRX_ID。

????????我們只需要拿read_view和DB_TRX_ID對比,就可以知道可以讀取的id。

????????最終根據隔離級別,可以獲得要讀取的id。

  • Creator_trx_id == DB_TRX_ID || DB_TRX_ID < up_limit_id

?????????在形成read view前已經提交的事務,形成的版本鏈數據,可以看到。

  • Up_limit_id <= DB_TRX_ID < low_limit_id

????????在形成read view時,正在執行的事務id保存在m_ids中。不在m_id中說明在形成快照前提交了,但是仍然在up_limit_id和low_limit_id范圍內。

????????注意:m_ids中的事務id不一定是連續的,可能由中間的事務ID已經提交了。比如:我們有11,12,13,14,15號事務。在形成快照前12,14號事務提交了。形成快照后,m_ids中保存的就是11,13,15。up_limit_id等于11,low_limit_id等于16。

????????此時如果DB_TRX_ID沒有m_ids中,說明已經提交(commit),可以被查詢。

? ? ? ? 如果DB_TRX_ID在m_ids中,說明還沒有被提交,不可以被查詢,

? ? ? ? 看下面源代碼就懂了。并且可重復讀和讀提交,是因為read? view不同,所以呈現的現象不同。下面有詳細介紹。

  • DB_TRX_ID >= low_limit_id

? ? ? ? 說明是形成read view后,形成的事務,對數據進行了修改。插入到了版本鏈中。

????????比如:此時有11,12,13,14,15號事務,形成read view。up_limit_id等于11,low_limit_id等于16。之后,又開始了一個事務16,并且修改了數據,所以版本鏈中會有大于low_limit_id的版本數據。

? ? ? ? 這種數據不能被查看。

?對應源碼策略:

  • ?id就是版本鏈中的DB_TRX_ID
  • Up_limit_id <= DB_TRX_ID < low_limit_id,只要m_ids中沒有id,就可以被查詢。?

注意:

  • read? veiw的作用就是用來判斷版本鏈中的數據是否可以看到。
  • 從版本鏈第一個結點開始查看,如果查到不應該看到的版本,就遍歷下一個版本,直到可以查看。
  • read view是進行可見性判斷的,即有了read view才直到哪些版本鏈的版本可見,哪些版本鏈的版本不可見。
  • read view是在select時,自動生成的。

MVCC流程演示,方便理解:

假設當前有一條記錄:

?事務操作:

事務1(id = 1)事務2(id = 2)事務3(id = 3)事務4(id = 4)
事務開始事務開始事務開始事務開始
.........修改并提交
進行中快照讀進行中
.........

事務修改了name,將name有張三修改成了李四。

當事務2對某行數據進行快照讀,數據庫為改行數據形成移和read view讀視圖。

該read view中保存的數據為:????????

????????m_id2 = {1,3};

????????up_limit_id = 1;

????????low_limit_id = 5;

????????creator_trx_id = 2;

版本鏈為:

只有事務4修改了數據,并在事務2快照讀前,提交了事務。

?事務2拿著版本鏈的DB_TRX_ID去跟up_limit_id和low_limit_id和活躍事務ID列表進行比較,判斷當前版本是否可以查看。

此時

該read view中保存的數據為:????????

????????m_id2 = {1,3};

????????up_limit_id = 1;

????????low_limit_id = 5;

????????creator_trx_id = 2;

DB_TRX_ID = 4

比較步驟:

  • DB_TRX_ID(4)? < up_limit_id(1)? 不小于,判斷下一個條件。如果小于可以查看。
  • DB_TRX_ID(4)?>= low_limit_id(5) ? 不大于,判斷寫一個條件。如果大于,不可以查看,遍歷版本鏈中的下一個結點。
  • m_ids.contains(DB_TRX_ID) ? 不包含,說明,事務4不在當前的活躍事務中。 此時就需要隔離級別來決定是否可以查看。 隔離級別為讀提交,可以查看,可重復讀,不可以查看。

?四.RR和RC的本質區別

?????????RR是可重復度,RC是讀提交。

? ? ? ? 對于表:

?設置當前會話的隔離級別為可重復讀

?介紹一個當前讀語法:

????????select *? ?from? ?表名? lock in share mode

案例1:?

事務A操作事務A描述事務B描述事務B操作
begin開啟事務開啟事務begin
select * from? student快照讀快照讀select * from? student
update student set age=30 where name='張三'更新名字為張三的年齡為30
commit提交事務
select沒有讀到張三的年齡為30select * from? student
select可以讀到張三的年齡為30select *? ?from? ?student? lock in share mode

?案例2:?

事務A操作事務A描述事務B描述事務B操作
begin開啟事務開啟事務begin
select * from? student快照讀,查到年齡為28
update student set age=30 where name='張三'更新名字為張三的年齡為30
commit提交事務
select可以讀到張三的年齡為30select * from? student
select可以讀到張三的年齡為30select *? ?from? ?student? lock in share mode

兩測試用例的區別:

  • 案例1在事務A提交和修改前,快照讀了一次。
  • 案例2在事務提交和修改前,沒有快照讀。

結論:

針對隔離級別是可重復讀(repeatable? read)

  • 事務中快照讀的結果是非常依賴該事務首次出現快照讀的地方,即某個事務中首次出現快照讀,決定該事務后續快照讀結果的能力。即,此時版本鏈中有多少結點。
可重復讀和讀提交本質區別: ??????? 首先強調: ????????源代碼中,如果Up_limit_id <= DB_TRX_ID < low_limit_id,只要不在m_ids中就可以被查詢。 ? ? ? ? read view是在快照讀的時候才形成的。
  • 在RR下,某個事務,只會對某條記錄的第一次快照讀會創建一個快照及Read view。
  • 之后在調用快照讀時,還是使用的同一個read? view,對形成read view之后的的修改是不可見的。
  • 在RC下,事務中,每一次快照讀都會新生成一個快照和read? view,這就是在RC級別下的事務中可以看到別的事務提交的更新的原因。
  • RR和RC區別是因為read? view的不同,RR只在第一次形成一個read veiw,并且之后都只會看這一個,而RC每一次快照讀都會形成read? view。

總結

以上是生活随笔為你收集整理的MySQL事务——万字详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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