關聯式資料庫與交易(Transaction)機制入門

更新日期: 2025 年 3 月 4 日

在現代應用開發中,關聯式資料庫(Relational Database)是最常見的數據存儲方式之一。

無論是企業管理系統、電商平台,還是社交媒體,關聯式資料庫都扮演著關鍵角色。

而在管理資料時,確保資料的一致性與可靠性是至關重要的,這正是「交易(Transaction)」的核心概念。

本篇文章將帶領初學者,了解關聯式資料庫的基本概念,以及交易的運作原理

幫助你建立扎實的基礎,為後續學習進階資料庫技術鋪路。


什麼是關聯式資料庫?

關聯式資料庫(Relational Database,簡稱 RDB)是一種基於關聯模型(Relational Model)的資料庫系統,其核心概念來自於數學中的「集合論」。

它以表格(Tables)的形式來儲存資料,透過行(Rows)與列(Columns)來組織數據,並透過關聯(Relationships)將不同表格的數據互相關聯。

關聯式資料庫的基本元素

關聯式資料庫的基本組成元素包括:

  • 表(Table):存放數據的主要結構,由行和列組成。
  • 行(Row):也稱為「記錄(Record)」,表示一筆具體的數據。
  • 列(Column):也稱為「欄位(Field)」,表示某一類型的數據。
  • 主鍵(Primary Key, PK):唯一標識每一筆記錄的欄位,如「使用者 ID」。
  • 外鍵(Foreign Key, FK):用來建立不同表格之間的關聯,如「訂單表」中的「使用者 ID」可以關聯到「使用者表」。

關聯式資料庫的優勢

使用關聯式資料庫的主要優勢包括:

  • 結構化數據管理:透過表格儲存與關聯設計,使數據更有條理。
  • 資料一致性與完整性:透過主鍵、外鍵與約束條件,確保數據的準確性。
  • 強大的查詢能力:支援 SQL(Structured Query Language),可高效檢索與操作數據。

什麼是交易(Transaction)?

當應用程式與資料庫進行數據操作時,往往不只涉及單一表格或單一筆資料。

例如,在銀行轉帳時,系統需要同時扣除 A 帳戶的餘額並增加 B 帳戶的餘額,這種涉及多筆數據的操作就需要「交易(Transaction)」來確保一致性。

交易的概念

交易(Transaction) 是資料庫操作的一個邏輯單位,確保一組相關的操作要麼全部成功,要麼全部失敗

這樣可確保資料不會因為系統故障或錯誤而變得不一致。

交易的 ACID 特性

為了確保數據的可靠性,交易需遵循 ACID 原則:

  • A(Atomicity,原子性):所有操作要麼全部執行,要麼全部回滾,不會發生「只執行部分操作」的情況。
  • C(Consistency,一致性):交易執行前後,數據的一致性必須維持,例如轉帳前後,銀行的總餘額不變。
  • I(Isolation,隔離性):不同交易之間彼此獨立,避免互相影響導致數據錯誤。
  • D(Durability,持久性):一旦交易提交,變更將永久存儲在資料庫中,不會因為系統崩潰而丟失。

交易的使用場景

  • 銀行轉帳:確保扣款與入款同時發生,否則回滾。
  • 電商訂單處理:確認付款成功後才建立訂單,否則取消。
  • 庫存管理:確保減少庫存與訂單建立同步完成。

如何在 SQL 中使用交易?

在關聯式資料庫中,交易通常透過 SQL 來管理,以下是常見的交易控制語句:

交易的基本操作

BEGIN TRANSACTION;  -- 開始交易
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;  -- 扣款
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;  -- 入款
COMMIT;  -- 提交交易

若某一步驟失敗,可以回滾交易:

BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 模擬錯誤
ROLLBACK;  -- 回滾交易

交易隔離級別(Transaction Isolation Levels)

在電商系統中,當多個顧客同時查詢、購買商品或進行付款時,資料庫需要確保數據的一致性,避免因為併發操作導致錯誤的結果。

例如,兩位顧客同時購買同一件商品,可能會導致超賣(Overselling),或者顧客查詢的價格與實際結帳時不同,影響購物體驗。

為了解決這些問題,資料庫提供了交易隔離級別(Transaction Isolation Levels),用來控制不同交易之間的影響。

交易隔離級別越高,能確保數據一致性的程度越高,但同時可能會降低系統效能。

因此,在不同的業務需求下,我們需要選擇適當的隔離級別來平衡數據一致性與系統效能

接下來,我們會透過電商購物的情境來說明每個隔離級別的運作方式,幫助你理解不同的交易隔離級別如何影響查詢與交易結果。

READ UNCOMMITTED(未提交讀)

情境:顧客查詢商品庫存

問題:可能會發生「髒讀(Dirty Read)」,讀到未提交的數據,導致顧客看到錯誤的庫存資訊。

📌 例子:

  1. 顧客 A 查詢「iPhone 15」的庫存,系統顯示 10 台(交易開始)。
  2. 顧客 B 購買 3 台 iPhone,系統執行 UPDATE 語句,將庫存數量改為 7 台,但交易尚未提交(COMMIT)
  3. 顧客 A 在未提交前再次查詢庫存,看到的是 7 台(因為讀到了還沒正式提交的數據)。
  4. 突然,顧客 B 取消訂單(ROLLBACK),庫存數量恢復為 10 台
  5. 但此時,顧客 A 看到的是錯誤的資訊(7 台),而不是實際的 10 台

這就是髒讀的問題,因為交易 A 讀到了未提交的變更,這些變更可能最終被取消,導致顧客 A 看到錯誤的資訊。

READ COMMITTED(已提交讀)

情境:顧客查詢商品價格

問題:可能會發生「不可重複讀(Non-Repeatable Read)」,即同一交易內的多次查詢結果不一致。

📌 例子:

  1. 顧客 A 查詢「MacBook Pro」的價格,顯示 $50,000(交易開始)。
  2. 商家 B 進行促銷活動,將「MacBook Pro」的價格改為 $45,000,並提交交易(COMMIT)。
  3. 顧客 A同一交易內再次查詢價格,這次顯示 $45,000

這時,顧客 A 在同一交易內查詢兩次,卻得到了不同的價格,這就是「不可重複讀(Non-Repeatable Read)」,因為數據在交易期間發生了變更。

📌 影響:

  • 如果顧客 A 在第一次查詢時決定購買,但在點擊「結帳」前價格已經變更,他可能會感到困惑或不滿。
  • READ COMMITTED 隔離級別雖然能避免髒讀,但無法保證查詢結果在同一交易內保持一致。

REPEATABLE READ(可重複讀)

情境:顧客查詢商品是否有折扣

問題:REPEATABLE READ 確保交易期間查詢結果一致,避免「不可重複讀」,但仍可能發生「幻讀(Phantom Read)」,即交易內的數據總數可能變化。

📌 例子:

  1. 顧客 A 在電商平台上查詢「特價商品清單」,系統顯示 AirPods 和 iPad 是目前正在促銷的商品(交易開始)。
  2. 商家另一個交易中新增了一個新的促銷商品 MacBook Pro,並提交交易(COMMIT)。
  3. 顧客 A同一交易內再次查詢特價商品,系統仍然只顯示 AirPods 和 iPad,因為 REPEATABLE READ 保證相同的查詢結果不會變動
  4. 顧客 A 完成結帳,系統生成訂單時,發現 MacBook Pro 其實也在特價清單內,但他在交易開始時並沒有看到這個商品。

📌 這就是「幻讀(Phantom Read)」的問題,因為交易開始時 MacBook Pro 並不在特價清單內,但在交易進行過程中,它被新增到資料庫,影響了交易的最終結果。

為什麼這是幻讀?

  • 不可重複讀(Non-Repeatable Read) 指的是相同的查詢在同一交易內返回不同的結果(例如,顧客 A 查詢價格,第一次看到 $50,000,第二次變成 $45,000)。
  • 幻讀(Phantom Read) 指的是查詢時原本沒有符合條件的數據,但在交易內卻突然多出了新的數據(例如,查詢特價商品時,原本沒有 MacBook Pro,但結帳時卻發現它也被加入特價清單)。

如何解決幻讀?

  • REPEATABLE READ 隔離級別下,顧客 A 看到的查詢結果會保持一致,但無法防止新商品被加入到促銷清單中
  • 如果要完全避免這種情況,就需要使用 SERIALIZABLE 隔離級別,這樣在顧客 A 的交易完成前,其他交易無法新增新的促銷商品,確保結果完全一致。

SERIALIZABLE(可串行化)

情境:秒殺活動的訂單處理

問題:確保交易彼此完全獨立,完全避免數據競爭,但可能降低效能。

📌 例子:

  1. 顧客 A 參加電商「限量秒殺」活動,查詢「PS5」的庫存,顯示 1 台(交易開始)。
  2. 顧客 B 也同時查詢「PS5」,看到的庫存也是 1 台(交易開始)。
  3. 顧客 B 先完成訂單並提交(COMMIT),這時庫存變為 0 台
  4. 顧客 A 嘗試購買 PS5,但因為 SERIALIZABLE 隔離級別的保護,這筆交易必須等 B 完成後才能執行,當 A 嘗試購買時,系統發現庫存為 0,導致交易失敗。

📌 影響:

  • 完全避免了競爭條件,確保 PS5 只會被「最早成功提交交易」的顧客買走,不會發生**超賣(Overselling)**的問題。
  • 由於交易必須排隊執行,如果有大量顧客同時購買,系統的效能可能會下降,導致顧客需要等待較長時間。

如何選擇適合的交易隔離級別?

隔離級別解決的問題可能發生的問題適用場景
READ UNCOMMITTED執行速度最快可能讀到錯誤數據(髒讀)低一致性要求,如瀏覽不重要的數據
READ COMMITTED避免讀到未提交的數據同一交易內可能查到不同結果(不可重複讀)一般電商應用,如商品查詢
REPEATABLE READ確保同一交易內的查詢結果一致可能發生幻讀(Phantom Read)訂單管理,確保庫存和價格不變
SERIALIZABLE確保數據完全一致,不會發生競爭效能最低,交易需要排隊執行高價值交易,如限量秒殺、銀行轉帳

如何設定交易隔離級別?

不同的資料庫管理系統(如 MySQL、PostgreSQL、SQL Server)允許開發者手動設定交易的隔離級別。在 SQL 中,你可以使用以下語法來設定隔離級別:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

你可以將 SERIALIZABLE 改成其他級別,例如:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

該選擇哪種隔離級別?

  • 如果你對資料一致性要求不高,且想要最快的執行速度READ UNCOMMITTED
  • 如果你想避免讀到未提交的錯誤數據(推薦一般應用使用)READ COMMITTED
  • 如果你希望同一交易內,查詢的數據不會變動REPEATABLE READ
  • 如果你想確保數據完全一致,並且願意犧牲效能SERIALIZABLE

在大多數應用中,READ COMMITTED 是一個良好的折衷方案,而 SERIALIZABLE 則適用於關鍵業務(如銀行交易)需要極高數據安全性的場景。


結論

關聯式資料庫是現代應用中最重要的數據存儲方式,而交易機制則確保數據在各種操作中維持一致性與可靠性。

透過學習交易的 ACID 特性SQL 交易管理方式,可以讓我們更好地理解如何設計穩定的資料庫應用。

希望本篇文章能幫助你對關聯式資料庫與交易有更清晰的概念,若你想進一步學習,可以開始練習 SQL 操作,並嘗試在實際應用中實施交易機制!🚀

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *