前言
事務是我們保證資料正确性的重要手段,隻要和資料庫打交道,就得了解它的 ACID 特性,這也是一個專業程式員應該掌握的基本技能。
事務是什麼?
在資料庫的世界裡,我們最常打交道的是 SQL 操作語句。然而,SQL 語句并不是資料庫的最小處理機關,事務才是。
事務包含了一條或多條 SQL 語句。這些 SQL 語句會被視為一個任務集合,而事務就保證了這個任務集合裡的 SQL 要麼全部執行完,要麼都不執行,不會讓資料處于一個中間操作狀态。

資料庫是面向多線程多使用者設計的,同一時刻會被多個程式讀取或修改。在并發操作時,需要考慮對同一資源的通路控制。而事務在這方面有完善的處理機制,後面将會提及到事務的隔離性。
另外,事務能保證資料的完整性,這包括邏輯上的完整以及實體上的完整性。
邏輯上的完整性是指不會存在中間狀态的資料;隻會成功或失敗復原。
實體上的完整性是指事務隻要執行成功,那麼即使重新開機也不會丢失執行結果。(當然,前提是資料檔案沒有損壞......)
事務的使用
事務的整體流程主要涉及到幾個狀态點:
(1)開始事務:BEGIN TRANSACTION;
(2)送出事務:COMMIT;
(3)復原事務:ROLLBACK;
一般的,當我們在執行一條 SQL 語句時就已經預設幫我們開啟了事務。若執行成功,則會送出事務。若執行失敗,則會復原事務。
其中,送出事務後,相對應的資料也會被持久化到硬碟上,即時重新開機也不會丢失。
事務的 ACID
前面提到過,事務能保證資料的完整性,它主要是通過 ACID 特性來保證的:
1、原子性(Atomicity)
事務是一個不可分割的機關,是以在一個事務裡的所有操作要麼全部生效,要麼全部不生效。
2、一緻性(Consistency)
也可以了解為是預期狀态的正确性,即從一個正确的狀态到另一個正确的狀态,這裡的狀态往往是由業務來定義的。
比如轉賬中的一個扣錢一個加錢,是我們規定的一個資料流轉,那麼執行前的賬戶餘額和轉賬後的賬戶餘額就得滿足加減特性,這就是所謂的業務正确。
3、隔離性(Isolation)
資料庫是允許多個事務并發執行的,每個事務在執行時理想狀态是互不影響。然而要達到這個效果就得串行執行事務,這樣并發能力也會大大降低。
是以,為了兼顧執行效率,将互相影響的程度分為了 4 個隔離級别:
1)未送出讀:
舉個例子,當事務 A 對表 1 進行更新操作後,有事務 B 讀取了更新後的資料,後面又由于某種原因,事務 A 進行了復原。
這樣對于事務 B 來講就依賴了一個無效的復原資料,進而後面所做出的決策,也不一定正确了,這就是所謂的髒讀,也就是未送出讀隔離級别,此級别資料一緻性最差,但并發性最好。
2)已送出讀:
如果想防止髒讀,就需要等待其他事務送出後再進行讀取操作。防止了無效的復原情況,這就是已送出讀隔離級别。
3)可重複讀:
已送出讀的隔離級别考慮到了資料復原的無效性,卻無法阻止事務的多次送出。
比如事務 A 不斷的對表進行修改送出,那麼事務 B 就會在不同的時間點讀取到不同的資料。
為了讓事務 B 在執行期間讀取的資料都是一緻的,就有了可重複讀的隔離級别,即事務 B 在執行期間,其他事務不得進行修改操作。
4)可串行化:
上面的可重複讀隔離級别保證了事務執行期間讀取的一緻性。然而這裡并不包括插入、删除操作。
即會出現讀多讀少資料的情況,這種現象叫做幻讀。
為了解決幻讀,隻得進行串行化執行事務,才能互不影響。而此時的事務并發性是最低的。
4、持久化(Durability)
最後一個事務特性就是持久化性。通過日志等手段,隻要我們的事務送出成功了,那麼就意味着這次的資料操作是成功的。即使下次重新開機了程式,也不會丢失此處的操作結果!
總結
事務的 ACID 特性保證了資料的完整性。其中,事務的隔離級别越高,資料一緻性越好,但并發能力就越差。這是需要我們在實際開發中取舍的。像日志記錄的讀取,使用髒讀就對總體影響不大。