Database Transaction & ACID

--

如果對後端領域有稍微接觸過的話,一定不會對資料庫的操作感到陌生,我們可以藉由 SQL 指令來進行資料的讀取、新增、修改、刪除…等操作。然而試想一下情境,如果是一個搶票系統,票卷開賣的瞬間一秒鐘可能會有無數個 db request 衝進來,這種狀況下資料的ㄧ致性就變得十分重要, 如果實際買票人數已經超過上限,資料庫系統在資料一致性上又沒有妥善處理,很可能會發生資料不正確的狀況,明明已經沒票了卻還是有大量的使用者買到票,到時候不只你的老闆會跑來罵你,顧客方一定也是抱怨連連的。不過別擔心,英雄存在的意義就是要解決一般人解決不了的問題,現在就馬上有請本篇的主角,同時也是解救資料不一致的英雄登場 — Transaction 交易。

(以下圖片皆出自讀書會成員 FuFu 的簡報)

什麼是 Transaction ?

Transaction,中文翻作交易或事務,是資料庫執行過程中的一個「邏輯單位」,一個 transaction 中包含多個對資料庫操作的行為,每個 transaction 有兩種可能的結局:全部執行成功 or 全部不執行(只要其中一個行為失敗就全部回滾)

Transaction 主要是解決需要一起發生的事件但事件或事件的參與者不同時或不一致的問題。

簡單來說 Transaction 存在有兩個主要目的:

  • 遭遇失敗時的時光機:想當初薩諾斯響指事件後復仇者們只能選擇回到過去無限寶石還沒收集完成的時間,想辦法改變未來,阻止響指的發生。Transaction 也能做到一樣的事,當 transaction 中有至少一個操作失敗時,整個 transaction 都會回滾(rollback),回到進行 transaction 「之前」的狀態。
  • 獨立作業的守護者:這部分我好像想不到什麼梗來比喻 XD主要就是解決上面所說資料庫一致性的難題,讓不同 transaction 可以獨立不受干擾 (Provide isolation between programs accessing a database concurrently)

聽起來很抽象,這邊還是不免俗提到一下通常講到 transaction 都會舉的例子:轉帳。

假設今天用戶 A 要將自己的 1000 元從台新銀行帳戶轉到玉山銀行帳戶,要執行的步驟會有兩個:1. 台新銀行帳戶扣款 1000 元 2. 玉山銀行帳戶收到款項,增加 1000 元。如果今天第一步成功第二步卻失敗會發生什麼事?用戶 A 的台新銀行帳戶就會少 1000 元,玉山銀行帳戶卻沒收到款項,總計白白損失 1000 元,真的慘。因此我們可以將以上的兩個步驟包在 transaction 當中,確保兩個步驟都成功才會完成,要是其中一個步驟失敗就會退到交易開始前的狀態,來避免資料不一致的悲劇發生。

Transaction 常見指令

  • START TRANSACTION:建立一個 transaction
  • COMMIT:TRANSACTION 中的操作結束時進行 commit
  • ROLLBACK:也就是上面提到的可以將交易回滾
Transaction simple example

Save Point 儲存點

除了上面的指令,也可以在交易中插入儲存點 (save point),有需要時可以 rollback 到儲存點,而不用 rollback 整個交易。基本指令如下:

建立儲存點:SAVEPOINT 儲存點名稱
刪除儲存點:RELEASE SAVEPOINT 儲存點名稱
rollback 回某個儲存點:ROLLBACK TO SAVEPOINT 儲存點名稱
save point simple example

Transaction 四大特性: ACID

接下來要講到 transaction 所具備的四個特性:

  • Atomicity 原子性
  • Consistency 一致性
  • Isolation 隔離性
  • Durability 永久性

一般常拿每個特性的英文開頭字母簡稱為 「ACID」。

小結 & 下回預告

今天簡單介紹了資料庫的 transaction (交易/事務) 的概念,包括它存在的目的與簡單的語法示範,也講到了 transaction 的 ACID 的特性,不過很遺憾的是,transaction 與 ACID 這四個特性並不能解決所有會遇到的難題,在併發的狀況下仍然會產生一些不預期的問題,因此下篇文章將會討論特定狀況下資料庫運作會遇到的一些操作錯誤,與介紹解決方法 — transaction 的四種隔離層級。

--

--

莫力全 Kyle Mo

什麼都想學的雜食性軟體工程師 🇹🇼 (https://github.com/kylemocode) 合作與聯繫 📪 oldmo860617@gmail.com IG 技術自媒體:@kylemo.webdev.life