MySQL事務(一)認識事務

簡單來說,事務就是要保證一組數據庫操作,要麼全部完成,要麼全部失敗。

為什麼要有事務

數據庫中的數據是共享資源,因此數據庫系統通常要支持多個用戶的或不同應用程序的訪問,會出現並發存取數據的現象。

數據庫系統必須對這種並發操作提供一種相應的處理機制來保證,訪問彼此之間不受任何干擾,從而保證數據庫的正確性不受到破壞,這種處理機制稱為「並發控制」。其中事務就是為了保證數據的一致性而產生的一種概念和手段。

事務特性

為了保證數據庫的正確性與一致性,事務要具有4個特性:

  • 原子性(atomicity):一個事務應該是一個不可分割的工作單位,事務中包括的操作要麼都成功,要麼都不成功。
  • 一致性(consistency):事務必須是使數據庫從一個一致性狀態變成另一個一致性狀態。一致性與原子性是密切相關的。
  • 隔離性(isolation):一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據在事務未提交前對並發的其他事務是隔離的,並發執行的各個事務之間不能互相影響。
  • 持久性(durability):一個事務一旦成功提交,它對數據庫中數據的改變就應該是永久性的。

並發事務存在的問題

如果不考慮事務的隔離性,會發生以下幾種問題:

臟讀

臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。

不可重複讀

不可重複讀是指在對於數據庫中的某條數據,一個事務範圍內多次查詢返回不同的數據值(這裡的不同是指某一條或多條數據的內容前後不一致,但數據條數相同)。

不可重複讀和臟讀的區別是:

  • 臟讀是某一事務讀取了另一個事務未提交的臟數據。
  • 不可重複讀是讀取了其他事務提交的數據。

幻讀

幻讀指的是一個事務在前後兩次查詢同一個範圍的時候,後一次查詢看到了前一次查詢沒有看到的行。

事務隔離級別

  • 讀未提交(read uncommitted):一個事務還沒提交時,它做的變更就能被別的事務看到。
  • 讀提交(read committed):一個事務提交之後,它做的變更才會被其他事務看到。
  • 可重複讀(repeatable read):一個事務執行過程中看到的數據,總是跟這個事務在啟動時看到的數據是一致的。當然在可重複讀隔離級別下,未提交變更對其他事務也是不可見的。
  • 串行化(serializable ):顧名思義是對於同一行記錄,「寫」會加「寫鎖」,「讀」會加「讀鎖」。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。

下面用一個例子來說明這四種隔離級別:

mysql> create table T(c int) engine=InnoDB;
mysql> insert into T(c) values(1);

假設表T只有一條記錄,值是1。我們來看看在不同的隔離級別下,事務A會有哪些不同的返回結果,也就是圖裏面T4、T6、T8的返回值分別是什麼。

  • 若隔離級別是「讀未提交」, 則T4的值就是2。這時候事務B雖然還沒有提交,但是結果已經被A看到了。因此,T6、T8也都是2。
  • 若隔離級別是「讀提交」,則T4是1,T6的值是2。事務B的更新在提交後才能被A看到。所以, T8的值也是2。
  • 若隔離級別是「可重複讀」,則T4、T6是1,T8是2。之所以T6還是1,遵循的就是這個要求:事務在執行期間看到的數據前後必須是一致的。
  • 若隔離級別是「串行化」,則在事務B執行「將1改成2」的時候,會被鎖住。直到事務A提交後,事務B才可以繼續執行。所以從A的角度看, T4、T6值是1,T8的值是2。

參數資料

Tags: