天天看點

資料庫事務、并發問題及隔離級别

目錄

      • 一、什麼是事務
      • 二、為什麼要使用事務
      • 三、事務并發問題
        • 1、髒寫
        • 2、髒讀
        • 3、不可重複讀
        • 4、幻讀
      • 四、事務的隔離級别
        • 1、讀未送出(READ UNCOMMITTED)
        • 2、讀已送出(READ COMMITTED)
        • 3、可重複讀(REPEATABLE READ)
        • 4、串行化(SERIALIZABLE)

一、什麼是事務

我們學習資料庫,經常看到資料庫事務,ACID事務等相關的概念,抛開資料庫,可以将事務更廣泛的定義為:一個或多個原子操作組合而成的執行單元。更通俗的講,就是将幾件小事或是幾個步驟捆綁起來作為一個整體來處理對待。

而資料庫事務,即一條或多條不可再分的資料操作指令組合而成的執行單元。一個标準的、合格的資料庫事務,應該需要滿足四個特性,即原子性(Atomicity)、一緻性(Consistency)、隔離性(Isolation)、持久性(Durability),這也就是所稱的ACID事務。

  • 原子性(Atomicity)

    原子性就是指的一個事務是一個整體,是不可再分的,事務中的所有指令要麼都執行成功,要麼都不執行。比如常見的各種闖關遊戲,你要麼一路不死闖關成功,要麼中途死了從頭再來。

  • 一緻性(Consistency)

    一緻性指的是一個事務執行,會将資料從一個一緻性狀态,變為另一個一緻性狀态。所謂的一緻性狀态,我更願意了解為一個應該是的狀态、一個符合現實邏輯關系的正确的狀态。比如"我們兩個各有一塊糖",執行一個事務"我搶了你一塊糖",就理應是變為"我有兩塊糖,你沒有糖"這個狀态,這前後就是兩個一緻性狀态。若結果變為了"我沒有糖,你有兩塊糖"或是其他,那就自然違背了一緻性了。

  • 隔離性(Isolation)

    隔離性是指當多個事務并發執行時,是互不影響的,即需要保證多個事務并發執行的結果,要與串行執行的結果相同。還是闖關遊戲的例子,我們兩個同時在兩台電腦上各自闖關,我的闖關過程和闖關結果對你應該是絲毫沒有影響的,不會因為我闖關成功而給你增加難度。而隔離性主要是為了解決事務引發的并發問題,下文将有介紹。

  • 持久性(Durability)

    持久性指的是事務送出後對資料庫的更新是不可逆的、持久化的,即使系統故障發生,也不會造成資料丢失。仍是闖關遊戲,我闖關成功就是闖關成功,不會我明天登入遊戲又回到了起點。

在四個事務特性中,資料的一緻性是最關鍵的,保證資料的一緻性是一個資料庫最基本的要求,同時也是事務這一個概念出現的一個重要原因,更是衡量一個事務是否合格的最重要的标準,也是事務最根本的追求。而影響事務一緻性的因素主要有事務并發問題和資料庫系統故障。說到底,其他三個特性,都是服務于保證資料一緻性而存在的。

二、為什麼要使用事務

事務的出現必然是為了解決某一問題。在使用DML(資料庫操作語言)或DDL(資料庫定義語言)使,多數情況下對資料的修改不是局限于一條記錄或是一張資料表的。

試想這麼一個簡單的圖書館借閱情景:A同學借了一本書a,在資料庫中我們要有必要的兩步操作,一是插入一條A借閱書a的記錄,二是把書a的庫存減一。

假若沒有事務,執行了第一個操作後,系統忽然出現故障沒能成功執行第二個操作,這樣導緻的結果是A借到了書a,但圖書館中書a的庫存卻沒有減少,是不符合邏輯,打破了資料的一緻性原則。

簡單來講,事務的出現就是将這兩個步驟捆綁在一起,實作的效果是:要麼兩個步驟都執行成功,要麼都不執行。進而保證了資料的一緻性。對于事務的使用,這裡引出兩個概念,一個叫事務的送出,即在事務成功執行後送出結束事務;一個叫事務的復原,即在事務執行過程中某個操作出現問題,恢複到事務執行之前的那個一緻性狀态。

而事務的出現,也帶來了不少事務并發問題,解決這些問題和追求ACID事務的目标是一緻的。

三、事務并發問題

事務帶來的并發問題常見的有以下四種情況

1、髒寫

髒寫是指兩個事務A、B,A更新資料還未送出,B也來更新資料。對于A來講,最終的資料不是自己想要更新的值。

髒寫問題使用行級排它鎖即可解決,在一條記錄被一個事務更新時,另外的事務是無法更新這條事務的。是以不再詳述。

2、髒讀

髒讀是至兩個事務A、B,A讀取了B更新尚未送出的内容,B事務復原,導緻A讀取的内容錯誤。如圖:

資料庫事務、并發問題及隔離級别

3、不可重複讀

不可重複讀是指兩個事務A、B,A讀取一個字段,B更新了這個字段,A再讀取一次這個字段,兩次讀取的結果不同。如圖

資料庫事務、并發問題及隔離級别

4、幻讀

幻讀是指兩個事務A、B,A讀取一個字段的行數,B插入或删除了某些記錄,A再讀取這個字段的行數,行數不同了。如圖

資料庫事務、并發問題及隔離級别

不可重複讀和幻讀問題十分相似,不可重複讀是并發事務B的UPDATE操作對事務A帶來的問題,幻讀是并發事務B的INSERT和DELETE操作對事務A帶來的問題。

四、事務的隔離級别

為了解決事務的并發問題,相應出現了SQL的隔離級别規範的概念。一般的,常見的隔離級别有以下四種,它們可以不同程度的解決事務的并發問題。

1、讀未送出(READ UNCOMMITTED)

允許事務A讀取事務B未送出的更新。自然,事務的并發工作流程是與以上三幅圖檔所示的流程一樣的,髒讀、不可重複讀、幻讀問題均不可實作。

2、讀已送出(READ COMMITTED)

隻允許事務A讀取事務B已經送出的更新。若B事務更改某條記錄未結束(送出或復原),A事務讀取相應記錄會阻塞至B事務結束。在個隔離級别下,髒讀問題圖示會變為:

資料庫事務、并發問題及隔離級别

3、可重複讀(REPEATABLE READ)

A事務讀取某個字段,在A事務操作期間,禁止B事務對該字段的更新。可重複讀解決事務的不可重複讀問題,這樣,流程圖變為:

資料庫事務、并發問題及隔離級别

4、串行化(SERIALIZABLE)

串行化即舍棄事務的并發處理能力,将所有事務串行執行,這樣雖然避免了所有的并發問題,但性能效率實在太低,一般不用。

資料庫事務、并發問題及隔離級别

四個隔離級别解決并發問題總結如下:

隔離級别 解決髒寫 解決髒讀 解決不可重複讀 解決幻讀

讀未送出

READ UNCOMMITTED

讀已送出

READ COMMITTED

可重複讀

REPEATABLE READ

串行化

SERIALIZABLE

四個隔離級别解決問題程度的遞增,是用犧牲資料庫的并發性能來得到的,如串行化級别,解決了所有的并發問題,但卻沒有任何并發能力。是以需要根據實際業務情況選擇合适的隔離級别。

還需要清楚,四個隔離級别隻是SQL給出的規範,包括前面所講的ACID事務的實作,每個資料庫存儲引擎對這些的實作技術都是不同的,所有引擎都在追求更高的隔離級别下的更高的并發能力。比如MySQL預設使用的InnoDB引擎,使用MVCC技術在可重複讀級别下,不用阻塞事務B的寫操作就可以解決不可重複讀甚至是幻讀問題。