Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

本文為「SQL 資料庫新手村」系列第 3 篇

資料庫入門:交易與鎖定——如何確保資料正確?

最後更新:2026年1月23日資料庫

前面的文章我們學到了:資料庫用「表格」來儲存資料,讓資料格式統一、位置固定、程式好處理。

但資料庫的好處不只這些。這篇文章要介紹資料庫另外兩個非常重要的功能——交易(Transaction) 和 鎖定(Lock)。

這兩個功能都是為了解決同一個問題:確保資料的正確性與一致性。

聽起來很專業?別擔心,讓我們用兩個 ATM 的故事來說明。

問題一:轉帳時資料不一致

情境:你要買東西,需要轉帳給賣家

假設你在網路上買了一個東西,要轉帳 2,000 元給賣家。

  • 你的帳戶餘額:10,000 元
  • 賣家的帳戶餘額:20,000 元

正常情況下,轉帳完成後應該是:

  • 你的帳戶餘額:8,000 元(扣掉 2,000)
  • 賣家的帳戶餘額:22,000 元(增加 2,000)

如果系統出了問題…

現在想像一個情況:轉帳過程中,系統出了一點問題。

賣家那邊的帳戶成功更新了,餘額變成 22,000 元。但不知道為什麼,你這邊的帳戶卻沒有被扣款,餘額還是 10,000 元。

結果變成:

  • 你的帳戶餘額:10,000 元(沒扣到!)
  • 賣家的帳戶餘額:22,000 元(已經增加)

這會造成什麼問題?

對你來說,這當然很爽——你平白多了 2,000 元。

但對銀行來說,這是一場災難。銀行憑空少了 2,000 元,而且這種錯誤如果一直發生,銀行很快就會倒閉。

反過來想,如果是你這邊被扣款了,但賣家那邊卻沒收到錢,那你就虧大了。

問題出在哪裡?

這個轉帳的動作,其實包含了兩個資料操作:

  1. 從你的帳戶「扣掉」2,000 元
  2. 在賣家的帳戶「增加」2,000 元

這兩個動作是綁在一起的,必須符合一個原則:

要嘛兩個都成功,要嘛兩個都不要發生。

不能只有一邊成功、另一邊失敗。

  • ✅ 兩邊都成功 → 正常轉帳完成
  • ✅ 兩邊都失敗 → 轉帳沒完成,但至少資料是對的
  • ❌ 只有一邊成功 → 資料不一致,出大問題!

什麼是交易(Transaction)?

資料庫提供了一個功能,叫做交易(Transaction)。

交易的定義

交易就是把「一組資料操作」綁在一起,當成一個整體來執行。

回到剛才的轉帳例子,這個動作其實包含兩個操作:

  1. 從你的帳戶扣掉 2,000 元
  2. 在賣家的帳戶增加 2,000 元

這兩個操作看起來是分開的,但它們在邏輯上是「一件事」——就是轉帳。如果只做了第一個、沒做第二個,或是只做了第二個、沒做第一個,都不算「轉帳完成」。

所以我們需要把這兩個操作「綁」在一起,告訴資料庫:「這是一筆交易,請一起處理。」

交易的規則

當你把多個操作包成一筆交易,資料庫會遵守一個規則:

全部成功,才算成功;只要有一個失敗,就全部取消。

什麼意思呢?

  • 如果所有操作都順利完成 → 資料庫才會把這些變更「正式寫入」
  • 如果其中任何一個操作失敗 → 資料庫會把已經做的操作「全部復原」,回到交易開始前的狀態

這個「復原」的動作,專業術語叫做回溯(Rollback)。

為什麼要這樣設計?

因為這樣可以確保資料永遠是「一致」的狀態。

以轉帳來說:

  • ✅ 你扣了錢,賣家也收到錢 → 資料一致,正確
  • ✅ 你沒扣錢,賣家也沒收到錢 → 資料一致,正確(只是轉帳沒成功)
  • ❌ 你扣了錢,賣家沒收到錢 → 資料不一致,錯誤!
  • ❌ 你沒扣錢,賣家卻收到錢 → 資料不一致,錯誤!

交易機制保證了:不會出現後面兩種「不一致」的情況。

用轉帳的例子來說明

當你發起一筆轉帳,資料庫會這樣處理:

開始交易

  1. 從你的帳戶扣掉 2,000 元
  2. 在賣家的帳戶增加 2,000 元
  
結束交易
  • 如果第 1 步和第 2 步都成功 → 交易完成,資料正式寫入
  • 如果第 1 步成功,但第 2 步失敗 → 整筆交易取消,第 1 步也會被回溯(rollback),你的帳戶餘額會恢復原狀
  • 如果第 1 步就失敗 → 交易直接取消,什麼都不會改變

這樣就能確保資料永遠是一致的,不會出現「一邊扣了、一邊沒加」的情況。

問題二:多人同時操作資料

情境:你和朋友共用一個帳戶

假設你和你的朋友共用同一個帳戶(現實中不太會發生,但我們用這個例子來說明)。

你們的帳戶餘額是 10,000 元。

有一天,你們兩個剛好同時在不同的 ATM 提款:

  • 你要提 6,000 元
  • 你的朋友要提 3,000 元

正常情況下,結果應該是:10,000 – 6,000 – 3,000 = 1,000 元

如果系統沒處理好…

假設這台 ATM 的程式寫得有點蠢,它的運作方式是:

  1. 先讀取目前餘額
  2. 計算提款後的新餘額
  3. 把新餘額寫回去

當你們同時操作時,會發生什麼事?

  1. 你登入 ATM,系統讀取餘額:10,000 元
  2. 同一時間,你朋友也登入 ATM,系統也讀取餘額:10,000 元
  3. 你提了 6,000 元,ATM 計算新餘額:10,000 – 6,000 = 4,000 元,寫回去
  4. 你朋友提了 3,000 元,ATM 計算新餘額:10,000 – 3,000 = 7,000 元,寫回去

最後餘額變成:7,000 元

資料怎麼出錯了?

你們兩個總共提了 9,000 元,但帳戶只少了 3,000 元!

問題出在哪裡?因為你朋友讀取餘額的時候,你的提款還沒完成,所以他看到的還是 10,000 元。等他寫回去的時候,就把你的操作結果覆蓋掉了。

對你們來說很爽,但對銀行來說又是一場災難。

什麼是鎖定(Lock)?

資料庫提供了另一個功能,叫做鎖定(Lock)。

鎖定的定義

鎖定就是:當某筆資料正在被操作時,禁止其他人同時操作這筆資料。

回到剛才的提款例子,問題出在哪裡?

你和朋友「同時」讀取了餘額,都看到 10,000 元。接著你們各自計算、各自寫回去,結果後寫的人把先寫的結果覆蓋掉了。

如果有鎖定機制,流程會變成:

  1. 你開始操作 → 資料庫把這筆資料「鎖住」
  2. 你朋友也想操作 → 資料庫說:「這筆資料被鎖住了,請等一下」
  3. 你完成操作 → 資料庫「解鎖」
  4. 你朋友現在可以操作了

就像上廁所要鎖門一樣——裡面有人的時候,外面的人就要排隊等。

鎖定的規則

鎖定的核心規則很簡單:

一次只能有一個人操作同一筆資料,其他人必須排隊等待。

這樣就能避免「同時操作、互相覆蓋」的問題。

鎖定的層級

鎖定可以有不同的範圍,根據你的需求來選擇:

  • 鎖定單筆資料(Row Lock):只鎖定正在操作的那一筆資料,其他筆資料不受影響
  • 鎖定整張表格(Table Lock):整張表的資料都不能被同時操作

通常會選擇「鎖定單筆資料」,因為這樣影響範圍最小。只有在特殊情況下,才會鎖定整張表格。

為什麼要這樣設計?

因為這樣可以確保資料不會被「同時修改」而出錯。

以提款來說:

  • ✅ 你先提款,朋友等你完成後再提款 → 餘額正確
  • ❌ 你和朋友同時提款,互相覆蓋 → 餘額錯誤

鎖定機制保證了:同一筆資料在同一時間只會被一個人修改,不會發生覆蓋的問題。

用提款的例子來說明

如果 ATM 有做鎖定,流程會變成:

  1. 你登入 ATM,系統讀取餘額:10,000 元,同時把這筆資料鎖住
  2. 你朋友也想登入,但系統發現這筆資料被鎖住了,告訴他:「有人正在操作,請稍後再試」
  3. 你提了 6,000 元,餘額更新為 4,000 元,解除鎖定
  4. 現在你朋友可以操作了,系統讀取餘額:4,000 元
  5. 你朋友提了 3,000 元,餘額更新為 1,000 元

最後餘額:1,000 元 ✅

這才是正確的結果!

鎖定的層級

鎖定可以有不同的範圍:

  • 鎖定單筆資料:只有這一筆資料不能被同時操作
  • 鎖定整張表格:整張表的資料都不能被同時操作

根據不同的需求,可以選擇適合的鎖定層級。

交易與鎖定的差異

這兩個功能都是為了確保資料正確,但解決的問題不太一樣:

交易(Transaction)鎖定(Lock)
解決的問題多個操作必須「一起成功或一起失敗」多個人不能「同時操作同一筆資料」
情境轉帳時,扣款和入帳必須同時完成提款時,不能讓兩個人同時改餘額
關鍵字全部成功,或全部回溯排隊,一個一個來
交易(Transaction)多個操作必須「一起成功或一起失敗」
鎖定(Lock)多個人不能「同時操作同一筆資料」
交易(Transaction)轉帳時,扣款和入帳必須同時完成
鎖定(Lock)提款時,不能讓兩個人同時改餘額
交易(Transaction)全部成功,或全部回溯
鎖定(Lock)排隊,一個一個來

實際上,這兩個功能常常會一起使用,來確保資料的完整性和一致性。

什麼時候需要交易和鎖定?

你可能會想:「這些功能聽起來很棒,那是不是所有系統都應該用?」

其實不一定。

交易和鎖定的代價

這兩個功能雖然能確保資料正確,但會影響效能:

  • 交易:系統要做很多檢查,確認所有操作都成功,失敗時還要回溯
  • 鎖定:其他人要排隊等待,不能同時操作

如果你的系統有很多人同時使用,這些機制可能會讓速度變慢。

什麼時候需要?什麼時候不需要?

需要交易和鎖定的情境:

  • 銀行轉帳、付款系統
  • 電商的庫存管理
  • 機票、飯店訂位系統
  • 任何「資料錯誤會造成嚴重損失」的情境

不一定需要的情境:

  • 社群網站按讚數(少算一個讚,其實沒什麼大不了)
  • 網站瀏覽次數統計
  • 任何「資料稍微不準確也可以接受」的情境

重點是:根據你的需求來決定要不要使用這些功能。

小結

資料庫提供了兩個重要功能來確保資料正確:

交易(Transaction)

  • 把多個操作綁在一起
  • 全部成功才算成功,有一個失敗就全部回溯
  • 解決「操作做到一半出錯」的問題

鎖定(Lock)

  • 當資料正在被操作時,禁止其他人同時操作
  • 一個一個排隊來
  • 解決「多人同時操作造成資料錯亂」的問題

這就是為什麼我們需要用資料庫——因為資料庫已經幫你把這些功能做好了,你不需要自己從頭寫。當你需要確保資料一致性的時候,直接用就可以了。

上一篇資料庫入門:為什麼資料要用表格儲存?
下一篇資料庫入門:認識表格的基本結構
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

資料庫

目錄

  • 問題一:轉帳時資料不一致
  • 情境:你要買東西,需要轉帳給賣家
  • 如果系統出了問題…
  • 這會造成什麼問題?
  • 問題出在哪裡?
  • 什麼是交易(Transaction)?
  • 交易的定義
  • 交易的規則
  • 為什麼要這樣設計?
  • 用轉帳的例子來說明
  • 問題二:多人同時操作資料
  • 情境:你和朋友共用一個帳戶
  • 如果系統沒處理好…
  • 資料怎麼出錯了?
  • 什麼是鎖定(Lock)?
  • 鎖定的定義
  • 鎖定的規則
  • 鎖定的層級
  • 為什麼要這樣設計?
  • 用提款的例子來說明
  • 鎖定的層級
  • 交易與鎖定的差異
  • 什麼時候需要交易和鎖定?
  • 交易和鎖定的代價
  • 什麼時候需要?什麼時候不需要?
  • 小結
  • 交易(Transaction)
  • 鎖定(Lock)