iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Software Development

埋藏在後端工程下的地雷與寶藏系列 第 18

Day-18 | Database ACID transaction(2) feat. 髒讀、不可重複讀、幻讀& Postgresql

  • 分享至 

  • xImage
  •  

今天接著昨天沒介紹完的 ACID

Atomicity 原子性

Atomicity,指的是 transaction 是一個單一個工作單元,原子性的 transaction 代表整個 transaction 中如果其中一個操作失敗,就會 fail 或重來。也就是只有完成和未完成兩種狀態,不會有中間的狀態。

Conststency 一致性

Conststency 確保每個 transaction 開始和結束時,資料庫都處於一致的狀態。換句話說,資料必須遵循所有的定義規則。完成一個 transaction 後,應轉到另一個一致的狀態。舉個例子,餘額不會有負數的出現,因此轉出的錢不能超過你的餘額,如果你轉出了餘額變負數,DB 就需要 ROLLBACK。

Isolation 隔離性

Isolation確保並發執行的 transaction 彼此之間不會互相影響。換句話說,transaction 在被提交 (commit) 前,其他 transaction 無法看到其未完成的結果。Isolation 避免了如髒讀(Dirty Reads)、不可重複讀(Non-repeating Reads)和幻讀(Phantom Read)等問題。

  • 髒讀:
    • 假設一個客戶的帳戶裡有 2000 元,客戶正在進行一個 transaction,匯出 200 元。此 transaction 已經寫入資料庫,但尚未提交 (commit)。這時,另一個使用者查看這個帳戶的餘額。如果他看到的餘額是 1800 元,那麼這就是髒讀 (dirty read),因為這筆 transaction 還未提交,未來可能會被 ROLLBACK。而隔離性較好的情況下,這位使用者應該只能看到原來的 2000 元,直到 transaction 完成並提交。
  • 不可重複讀:
    • 不可重複讀是指在一個 transaction 中,對同一筆資料進行多次查詢時,讀取到的結果不一致,因為另一個 transaction 在查詢期間修改了這筆資料。
    • 假設你的帳戶有 2000 元,你執行一個transaction) 要匯款 2000 元。transaction 首先會查詢你的帳戶餘額,確認有足夠金額進行匯款。這時系統查詢到你的餘額是 2000 元,判定足夠匯款。接著在匯款過程中,另一個transaction 在你的帳戶中提走了 500 元,這時當系統再次確認帳戶餘額時,發現餘額只有 1500 元,導致匯款失敗。
  • 幻讀:
    • 幻讀指在一個 transaction 中,多次查詢某一條件範圍內的資料時,由於另一個 transaction 插入或刪除了滿足該條件的記錄,導致查詢結果的數量發生變化,就像幻影般多出來的新紀錄 XD。
    • 假設使用者在一個 transcation A 查詢所有餘額大於 2000 元的帳戶,結果查詢到 10 個帳戶。此時,使用者 B 創建了一個新帳戶,並將該帳戶的餘額設為 2300 元,然後提交了 transaction。這時使用者 A 在同一個 transaction 中再次查詢餘額大於 500 元的帳戶,結果變成了 6 個帳戶。這樣的差異就可能會影響這個 transaction 原本可能執行後的結果。
  • Isolation level 隔離層級
    • Read Uncommitted:
      • 允許讀取未提交的變更,可能導致髒讀。
    • Read Committed:
      • 只允許讀取已提交的變更,但可能發生不可重複讀。
      • 避免髒讀
    • Repeatable Read:
      • 保證在一個 transaction 內,多次讀取同一行資料的結果一致,避免不可重複讀。
      • 可以避免不可重複讀。
    • Serializable:
      • 提供最高的隔離性,確保 transaction 以串行方式執行,完全避免並發問題。
      • 可以避免幻讀
        -以下為整理好的表格,根據不同的系統和要求通常至少會是 Read Committed 以上的隔離層級。
隔離層級 Dirty Read Unrepeatable Read Phantom Read
Read uncommitted YES YES YES
Read committed NO YES YES
Repeatable read NO NO YES
Serializable NO NO NO
  • Postgresql 的 isolation level
    • Postgresql 中預設是使用 Read committed。
ithome=# SHOW TRANSACTION ISOLATION LEVEL;
 transaction_isolation
-----------------------
 read committed
  • 修改 isolation level
    • 可以在每次 transaction 設定單次的
    • 也可以在 postgresql.conf 裡修改

單次的操作

BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
這裡是 transaction 操作
COMMIT;

https://ithelp.ithome.com.tw/upload/images/20241002/20150927ptE1dOnwtQ.png

直接修改 postgresql.conf
restart postgresql 後再回到 DB
可以看到修改完後就會是 serializable

ithome=# SHOW TRANSACTION ISOLATION LEVEL;
 transaction_isolation
-----------------------
 serializable

Durability 持久性

Durability,指的就是變更寫入資料庫後,資料的修改就不會變了,即便系統故障也不會丟失。

Reference


上一篇
Day-17 | Database ACID transaction(1)
下一篇
Day-19 | ORM & N+1 problem
系列文
埋藏在後端工程下的地雷與寶藏30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言