深入理解資料庫事務:確保資料完整性與一致性

2023-08-22 06:01:23

前言

在現代資訊系統中,資料是至關重要的資產之一。作為一名後端開發人員,與資料庫的交道必不可少,為了確保資料的完整性、一致性和可靠性,資料庫引入了事務的概念。本次將帶您深入瞭解資料庫事務的重要性、特性以及如何在應用程式中正確地使用事務來維護資料的穩定性。

什麼是資料庫事務?

資料庫事務是一組資料庫操作的集合,這些操作要麼全部成功執行,要麼全部失敗回滾。事務是資料庫管理系統(DBMS)中的核心概念,用於確保資料在並行存取和操作時的一致性和完整性。

ACID 特性

事務通常遵循 ACID 特性,這是指:

  • 原子性(Atomicity):事務中的操作要麼全部成功,要麼全部失敗。如果任何操作失敗,整個事務都會回滾,保持資料的一致性。

假設您正在購物超市,您選擇了一些商品放入購物籃。原子性就像是您在結賬時,要麼所有商品都被正確地掃描和計算,要麼沒有商品被結賬,就像是所有商品一起被稱為一個「原子」單位。

  • 一致性(Consistency):事務將資料庫從一個合法狀態轉換為另一個合法狀態,不會違反資料完整性約束。

在購物過程中,超市會檢查您購物籃中的商品是否與價格一致,以確保不會因為錯誤標價而導致不一致的情況。一致性就像是超市保持商品和價格一致,您購買的商品總是符合預期。

  • 隔離性(Isolation):並行執行的事務相互隔離,一個事務的操作不會影響其他事務,直到事務提交才對其他事務可見。

想象您和朋友同時在超市購物,但您的購物籃和朋友的購物籃是分開的,互不干擾。這就是隔離性,不同的購物籃(事務)在彼此之間是隔離的,不會相互干擾

  • 永續性(Durability):一旦事務提交,其對資料庫的更改將永久儲存,即使系統崩潰也不會丟失。

假設您購買了商品並完成了結賬,超市會將您購買的記錄存檔,以備將來查詢。即使您離開超市,您的購買記錄仍然被保留,就像是您的購物資訊被「持久」儲存

事務的基本操作

一個典型的事務通常包括以下步驟:

  1. 開始事務(BEGIN):事務開始前,DBMS 記錄當前狀態以備後用。

  2. 執行操作(Perform Operations):在事務內執行資料庫操作,如插入、更新、刪除等。

  3. 提交事務(COMMIT):如果事務內的所有操作都成功完成,可以將事務提交,將更改永久儲存到資料庫中。

  4. 回滾事務(ROLLBACK):如果在事務執行期間發生錯誤,可以回滾事務,撤消之前的操作,將資料庫恢復到事務開始前的狀態。

事務的隔離級別

事務隔離級別控制了事務之間的可見性和並行行為。常見的隔離級別包括:

  • 讀未提交(Read Uncommitted):在這個隔離級別下,一個事務可以讀取其他事務尚未提交的資料。這可能導致髒讀(讀取了未提交的資料)、不可重複讀(同一查詢在事務執行期間返回不同結果)和幻讀(事務在同一查詢中看到不同的資料行)等問題。讀未提交的隔離級別最不嚴格,可能會引發資料不一致問題

  • 讀已提交(Read Committed):在這個隔離級別下,一個事務只能讀取已經提交的資料,避免了髒讀問題。但是,不可重複讀和幻讀問題仍然可能出現。因為其他事務可能在事務進行期間提交新的資料,導致不同時間點的查詢結果不一致。

  • 可重複讀(Repeatable Read):可重複讀隔離級別確保在同一事務內,同一個查詢的結果保持一致。這意味著一個事務中的查詢不會受到其他事務的修改影響。這可以防止髒讀和不可重複讀問題,但幻讀問題仍然可能出現,因為其他事務可能插入新資料,導致新資料行的出現。

  • 序列化(Serializable):序列化是最嚴格的隔離級別,它確保每個事務都在獨立的時間段內執行,防止了並行問題。事務按照順序一個接一個地執行,這可以解決髒讀、不可重複讀和幻讀問題。然而,序列化可能會對效能產生較大的影響,因為事務需要依次執行。


上面說到事務的隔離級別可以解決髒讀、幻讀、不可重複讀的問題。那麼什麼是髒讀、幻讀、和不可重複讀呢?

  • 髒讀(Dirty Read)
    髒讀指的是在一個事務中讀取了另一個事務未提交的資料。假設事務 A 修改了某一行資料,但還沒有提交。同時,事務 B 嘗試讀取了事務 A 修改的資料。如果事務 A 最終回滾了,那麼事務 B 讀取的資料就是不存在的,這就是髒讀。髒讀會導致不準確的資料展示,因為讀取的資料可能是臨時的、未經驗證的。

想象你正在製作一個蛋糕,但在製作過程中,你的朋友看了一眼,然後走了。在他離開之前,你還沒有完成蛋糕,但他已經看到了不完整的狀態。這就好像是一個「髒讀」:朋友讀取了還沒有完成的資訊,結果可能是不準確或臨時的。

  • 不可重複讀(Non-repeatable Read)
    不可重複讀是指在同一個事務內,多次讀取同一資料時,得到不同的結果。這可能是因為在事務執行期間,其他事務修改了資料。例如,事務 A 在讀取某一行資料後,事務 B 修改了這行資料,並提交了。現在事務 A 再次讀取相同的資料,發現資料已經不同了,造成了不一致的現象。

假設你正在讀一本小說,當你讀到一部分內容時,有人偷偷地在書的後面新增了一些新章節。如果你再次閱讀同一部分,你會發現內容已經改變了,因為有新的內容被新增進來。這就像是「不可重複讀」:同樣的資料在短時間內發生了變化,導致你得到了不同的結果。

  • 幻讀(Phantom Read)
    幻讀是指在同一個事務內,多次查詢同一範圍的資料時,得到不同的結果。這與不可重複讀類似,但幻讀關注的是資料的數量變化。例如,事務 A 在查詢某個範圍內的所有資料時,事務 B 插入了新資料,並提交了。現在事務 A 再次查詢同一範圍的資料,發現資料行的數量增加了,這就是幻讀。

想象你正在草地上採摘草莓,你數了一下有多少個成熟的草莓。然後你去拿一個籃子,當你回來時,發現有一些新的草莓從草叢裡冒出來,導致總數增加了。這就是「幻讀」:同一範圍內的資料在短時間內發生了變化,導致數量發生了變化。

事務的傳播行為

事務的傳播行為是指在多個事務邊界互動時,一個事務如何與另一個事務進行互動和傳播。傳播行為定義了事務的範圍、邊界和巢狀關係,以確保事務的一致性和正確性。以下是幾種常見的事務傳播行為:

  • PROPAGATION_REQUIRED(需要事務)
    這是預設的傳播行為。如果當前沒有事務,就建立一個新事務;如果已經存在事務,就加入該事務。這意味著如果方法被呼叫時沒有事務,則會建立一個新事務。如果方法已經在事務中,則方法將使用已經存在的事務。這樣做可以保證事務巢狀。

這就像您和朋友在一起製作一張拼圖。如果朋友已經在拼圖上工作(存在事務),您會加入他的工作。如果沒有人在拼圖,您會建立一個新的拼圖,然後加入製作過程。這樣,無論之前是否有拼圖,您都可以保證最終拼圖是一張完整的。

  • PROPAGATION_REQUIRES_NEW(需要新事務)
    無論當前是否存在事務,都會建立一個新的事務。如果方法已經在事務中,則當前事務會被掛起,新事務將建立。這樣做可以在方法執行期間獨立於外部事務建立一個新的事務,確保完全隔離。

這就像您與朋友們一起在不同的活動中度過週末。無論朋友們在做什麼活動(存在事務),您都決定自己嘗試一項新活動,不受其他人的影響。您可以全身心地投入新的活動,不必擔心與其他活動的衝突。

  • PROPAGATION_NESTED(巢狀事務)
    如果當前存在事務,則在該事務內巢狀一個新事務。如果沒有事務,則行為類似於 PROPAGATION_REQUIRED。巢狀事務可以回滾到巢狀點,而不會影響外部事務。這樣可以實現更細粒度的事務管理。

想象您和家人一起做一個家庭專案,同時每個家庭成員也在做各自的小專案。您的小專案被巢狀在整個家庭專案中。您的專案可以獨立完成,但仍然受到家庭專案的影響。如果家庭專案失敗,您的專案也會受到影響。

  • PROPAGATION_SUPPORTS(支援事務)
    如果當前存在事務,則加入該事務;如果沒有事務,則以非事務方式執行。這意味著方法將根據呼叫方的上下文來決定是否執行在事務中。

這就像您加入一個跳繩團隊的訓練。如果其他人正在跳繩(存在事務),您可以選擇加入他們的活動。如果沒有人在跳繩,您可以以非正式的方式自己練習,不需要參與到團隊的事務中。

  • PROPAGATION_NOT_SUPPORTED(不支援事務)
    以非事務方式執行方法。如果當前存在事務,則將其掛起,方法執行完畢後恢復原事務。這樣可以保證方法的執行不受外部事務的影響。

這就像您在休閒時間去運動,不受任何工作的干擾。無論別人是否在工作,您可以專注於自己的活動,沒有事務的干擾。

  • PROPAGATION_MANDATORY(強制性的事務)
    必須在一個已存在的事務中執行,否則將丟擲異常。這樣可以確保方法在事務上下文中被呼叫。

這就像您參加一個要求穿制服的活動。您必須穿制服(存在事務)才能參與,否則將無法參加。

  • PROPAGATION_NEVER(不允許事務)
    必須在非事務環境中執行,否則將丟擲異常。這樣可以確保方法不會被錯誤地巢狀在事務中。

這就像您在一個休息時間內,被告知不能工作。無論其他人是否在工作,您不能參與到事務中。

如何正確使用事務?

在應用程式中,正確使用事務至關重要。以下是一些指導原則:

  1. 小而短的事務:將事務保持儘可能小和短,以減少對資料庫資源的鎖定時間,提高並行效能。

  2. 適當的隔離級別:選擇適當的隔離級別,平衡資料的一致性和效能需求。

  3. 例外處理:捕獲和處理事務中的異常,以便在錯誤發生時能夠正確地回滾事務。

  4. 批次操作:對大量資料進行操作時,考慮使用批次操作,減少事務的數量,提高效能。

  5. 事務巢狀:某些資料庫支援事務巢狀,但必須小心使用,確保正確的提交和回滾順序。

總結

事務是資料庫管理中保證資料一致性和完整性的重要工具。通過遵循 ACID 特性、正確使用事務操作和選擇適當的隔離級別,我們可以確保應用程式的資料在並行環境下保持穩定。深入理解和正確使用資料庫事務,將使您的應用更加可靠、穩定和高效。