天天看點

資料庫事務特性和隔離級别

1. 事務的定義

  資料庫事務是資料庫管理系統執行過程中的一個邏輯機關,有一個有限的資料庫操作序列完成。以 “A賬戶向B賬戶彙錢” 為例,一個事務是下面一個操作序列:

  a. 從A賬号中把餘額讀出來。

  b. 對A賬号做減法操作。

  c. 把結果寫回A賬号中。

  d. 從B賬号中把餘額讀出來。

  e. 對B賬号做加法操作。

  f.  把結果寫回B賬号中。

2.事務的特性(ACID)

  事務有四大特征,分别為原子性(Atomic),一緻性(Consistency),隔離性(Isolation),持久性(Durability)。

原子性(Atomic):

事務中包含的操作被看做一個邏輯單元,這個邏輯單元中的操作要麼全部成功,要麼全部失敗復原。事務的原子性也展現在事務對資料的讀取上,例如一個事務對同一資料項的多次讀取的結果一定是相同的。

一緻性(Consistency):

一緻性是指事務必須使資料庫從一個一緻性狀态變換到另一個一緻性狀态,也就是說一個事務執行之前和執行之後都必須處于一緻性狀态。比如,假設使用者A和使用者B兩者的錢加起來一共是5000,那麼不管A和B之間如何轉賬,轉幾次賬,事務結束後兩個使用者的錢相加起來應該還得是5000,這就是事務的一緻性。

有些時候這種一緻性由資料庫的内部規則保證,例如資料的類型必須正确,資料值必須在規定的範圍内,等等。

另外一些時候這種一緻性由應用保證的,例如,** 一般情況下銀行賬務餘額不能是負數,信用卡消費不能超過該卡的信用額度等。**

隔離性(Isolation):

事務允許多個使用者對同一個資料進行并發通路,而不破壞資料的正确性和完整性。

同時,并行事務的修改必須與其他并行事務的修改互相獨立。

事務的隔離性一般由事務的鎖來進行控制。

許多時候資料庫在并發執行多個事務,每個事務可能需要對多個表進行修改和查詢,與此同時,更多的查詢請求可能要在執行。資料庫需要保證每一個事務在它的修改全部完成之前,對其他的事務是不可見的。

換句話說,不能讓其他事務看到該事務的中間狀态,例如,從銀行賬戶A轉一比款項a到賬戶B,不能讓其他事務(例如賬戶查詢)看到A賬戶已經扣除款項a但B賬戶卻沒有增加款項a的狀态。

持久性(Durability):

事務結束後,事務處理的結果必須能夠得到固化,即使系統出現各種異常也是如此。

即一個事務一旦被送出了,那麼對資料庫中的資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丢失送出事務的操作。

3.資料庫的隔離級别

在多線程并發的環境下,當有多個線程都開啟事務操作資料庫中的資料時,資料庫系統要能夠進行隔離操作,以確定各個線程擷取資料的準确性。否則,可能會出現以下幾種問題:

  • 更新丢失(Lost Update)

當兩個或多個事務選擇同一行,然後基于最初標明的值更新該行時,由于每個事務都不知道其他事務的存在,就會發生丢失更新問題——最後的更新覆寫了其他事務所做的更新。例如,兩個編輯人員制作了同一文檔的電子副本。每個編輯人員獨立地更改其副本,然後儲存更改後的副本,這樣就覆寫了原始文檔。最後儲存其更改儲存其更改副本的編輯人員覆寫另一個編輯人員所做的修改。如果在一個編輯人員完成并送出事務之前,另一個編輯人員不能通路同一檔案,則可避免此問題。通常,“更新丢失”在并發事務進行中通常是完全避免的。

  • 髒讀(Dirty Reads)

髒讀是指在一個事務處理過程裡讀取了另一個未送出的事務中的資料。

當一個事務正在多次修改某個資料,而在這個事務中這多次修改還都未送出時,一個并發的事務來通路該資料,就會造成兩個事務得到的資料不一緻。

  • 不可重複讀(Non-Repeatable Reads)

不可重複讀是指在對于資料庫中的某個資料,一個事務範圍内多次查詢卻傳回了不同的資料值,這是由于在查詢間隔,資料被另一個事務修改并送出了。

不可重複讀和髒讀的差別是,髒讀是某一事務讀取了另一個事務未送出的髒資料,而不可重複讀是讀取了前一個事務送出了的資料。

  • 幻讀(虛讀)(Phantom Reads)

幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”并且送出給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像産生幻覺一樣,這就是發生了幻讀。

幻讀和不可重複讀都是讀取了另一條已經送出的事務(髒讀不同),所不同的是不可重複讀查詢的都是同一個資料項,而幻讀針對的是一批整體資料。

接下來看看MySQL提供的四種隔離級别:

  1. Serializable(串行化):可避免髒讀、不可重複讀、幻讀的發生
  2. Repeatable read(可重複讀):可避免髒讀、不可重複讀的發生
  3. Read committed(讀已送出):可避免髒讀的發生
  4. Read uncommitted(讀未送出):最低級别,無法避免

這四種級别最高的是Serializable,最低的是Read uncommitted,級别越高,執行效率越低。MySQL的預設級别為Repeatable Read.

需要注意的是,這四種級别都要求當一個事務在進行寫操作時,不允許其他事務進行寫操作,可通過“排他寫鎖”實作。

實作這四種隔離級别需要采取不同類型的鎖,本文隻關心事務特性和隔離級别,關于如何實作隔離級别,将在後續的文章中探讨。

繼續閱讀