天天看點

MYSQL事務篇(進階篇)

一般是指要做的或所做的事情。 在計算機 術語 中是指通路并可能更新資料庫中各種 資料項 的一個程式 執行單元 (unit)

ACID是以下4個詞的縮寫:

原子性(atomicity) :事務最小工作單元,要麼全成功,要麼全失敗 。

一緻性(consistency): 事務開始和結束後,資料庫的完整性不會被破壞 。

隔離性(isolation) :不同僚務之間互不影響,四種隔離級别為RU(讀未送出)、RC(讀已送出)、RR(可重複讀)、SERIALIZABLE (串行化)。

持久性(durability) :事務送出後,對資料的修改是永久性的,即使系統故障也不會丢失 。

四種隔離級别分别為:

  1)未送出讀(READ UNCOMMITTED/RU) 如果一個事務讀到了另一個未送出事務修改過的資料,那麼這種 隔離級别 就稱之為 未送出讀 會産生髒讀的情況

  2)   已送出讀(READ COMMITTED/RC) 不可重複讀:一個事務因讀取到另一個事務已送出的update。導緻對同一條記錄讀取兩次以上的結果不一緻。

  如果一個事務隻能讀到另一個已經送出的事務修改過的資料,并且其他事務每對該資料進行一次修改并送出後,該事務都能查詢得到最新值,那麼這種 隔離級别 就稱之為 已送出讀,會産生幻讀的情況。

  3)可重複讀(REPEATABLE READ/RR) 在一些業務場景中,一個事務隻能讀到另一個已經送出的事務修改過的資料,但是第一次讀過某條記錄後,

  即使其他事務修改了該記錄的值并且送出,該事務之後再讀該條記錄時,讀到的仍是第一次讀到的值,而不是每次都讀到不同的資料。那麼這種 隔離級别 就稱之為 可重複讀,會産生幻讀的情況。

  4)串行化(SERIALIZABLE) 最高的預設級别,強制事務串行執行(即一個事務一個事務執行)。效率極其低下。

 比如現在有一個例子:

一個轉賬的一個案例:

丢失更新

兩個事務針對同一資料都發生修改操作時,會存在丢失更新問題。

MYSQL事務篇(進階篇)

使用LBCC(LBCC,基于鎖的并發控制,英文全稱Lock Based Concurrency Control)可以解決上述的

問題。查詢總額事務會對讀取的行加鎖,等到操作結束後再釋放所有行上的鎖。因為使用者A的存款被鎖,導緻轉賬操作被阻塞,直到查詢總額事務送出并将所有鎖都釋放。

示例:這種方案比較簡單粗暴,就是一個事務去讀取一條資料的時候,就上鎖,不允許其他事務來操作

MYSQL事務篇(進階篇)

MVCC(MVCC,多版本的并發控制,英文全稱:Multi Version Concurrency Control)機制可

以解決這個問題。查詢總額事務先讀取了使用者A的賬戶存款,然後轉賬事務會修改使用者A和使用者B賬戶存

款,查詢總額事務讀取使用者B存款時不會讀取轉賬事務修改後的資料,而是讀取本事務開始時的資料副本(在REPEATABLE READ隔離等級下)

隻支援RC,RR隔離級别。

示例:MVCC使得資料庫讀不會對資料加鎖,普通的SELECT請求不會加鎖,提高了資料庫的并發處理能力

MYSQL事務篇(進階篇)

MVCC是用于資料庫提供并發通路控制的并發控制技術MVCC最大的好處:相信也是耳熟能詳:讀不加鎖,讀寫不沖突。

多版本并發控制僅僅是一種技術概念,并沒有統一的實作标準,

其核心理念就是資料快照,不同的事務通路不同版本的資料快照,進而實作不同的事務隔離級别。

是一個復原日志就是送出一些未送出操作的原始狀态 然後它會記錄版本号 :

如果有主鍵是2個隐藏列 如果沒有則是3個隐藏列

隐藏列呢就是三個部分組成

1.rowid:如果沒有主鍵則會自動生産

2.復原指針:指向記錄的上一個版本号

3.事務id:記錄了操作這條事務的id(這個id是唯一的而且是自增的) 然後每次更新都會有生産一個新版本通過復原指針指向舊版本 形成一個版本鍊

執行删除操作的時候是不會直接删除的是進行了一個打了一個删除标記,真正删除是通過purge線程執行清除操作的

相當于一個快照,隻要readview不改變則讀取的結果就是一樣的

readview生産時刻就是執行select操作時生産的一個select對應一個ReadView select執行完畢那麼ReadView就會失效

它就是一個數組(m_ids) 記錄了目前時刻資料庫活躍的事務id清單,它的可見性判斷呢可以根據m_ids與事務id進行判斷 判斷條件可以根據(如果都可讀以最新版本為準):

  

MYSQL事務篇(進階篇)

句個列子比如:

MYSQL事務篇(進階篇)

 如果資料庫沒有活躍的事務,那麼ReadView(m_ids)中包含的就是将要生成的事務id。

1.SELECT

InnoDB 會根據以下兩個條件檢查每行記錄:

1. InnoDB隻查找版本早于目前事務版本的資料行(也就是,行的事務編号小于或等于目前事務的事務編号)

 這樣可以確定事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的。

2. 删除的行要事務ID判斷,讀取到事務開始之前狀态的版本。

隻有符合上述兩個條件的記錄,才能傳回作為查詢結果。

2.INSERT

InnoDB為新插入的每一行儲存目前事務編号作為行版本号。

3.DELETE

InnoDB為删除的每一行儲存目前事務編号作為行删除辨別。

4.UPDATE

InnoDB為插入一行新記錄,儲存目前事務編号作為行版本号,同時儲存目前事務編号到原來的行作為行删除辨別。

讀已送出:目前事務可以讀取其他事務送出的結果

實作方案:目前事務執行select語句時會生産一個ReadView,如果再次執行這個selct語句繼續生成ReadView。

可重複讀:目前事務中執行的select語句的多次執行結果都是相同的,不管其他事務有沒有送出。

實作方案:在目前事務執行select語句生産一個ReadView,之後同一個select使用同一個ReadView

READ COMMITTD 、 REPEATABLE READ 這兩個隔離級别的一個很大不同就是生成 ReadView 的時機不同

READ COMMITTD 在每一次進行普通 SELECT 操作前都會生成一個 ReadView

而 REPEATABLE READ 隻在第一次進行普通 SELECT 操作前生成一個 ReadView ,之後的查詢操作都重複這個 ReadView就好了。

在REPEATABLE READ隔離級别下,MVCC具體是如何操作的。

繼續閱讀