跳轉到

Go Transaction Atomicity Patterns

概念概覽

三種典型 Transaction 邊界錯誤

核心知識

三種典型 Transaction 邊界錯誤

1. Read Outside Transaction(Stale Snapshot)

AdminRemoveItem 在 tx 外讀取 item.Quantity,開 tx 後資料可能已被其他 goroutine 修改。 規則:需讀寫同一筆資料時,read 必須在 transaction 內部

2. 多步驟操作非 Atomic

useInBattleItem 扣背包 + UpdateItemUsageLog 分屬兩個操作,失敗時無法一起 rollback。 規則:「扣資源」與「記錄扣除原因」必須在同一個 transaction。

3. GDPR Soft-Delete 不 Atomic

gdpr_service.go soft-delete 資料列與建立 deletion task 分兩步執行,若中間崩潰會產生孤立的 soft-deleted 記錄(task 不存在,資料不會被真正刪除)。 規則:任何「狀態標記 + 後續任務建立」的組合都必須在同一 DB transaction。

反模式識別

// WRONG: read outside tx
item, _ := repo.GetItem(ctx, itemID)  // <-- stale snapshot
tx, _ := db.Begin(ctx)
tx.UpdateItem(ctx, item.ID, item.Quantity-1)

// CORRECT: read inside tx
tx, _ := db.Begin(ctx)
item, _ := tx.GetItemForUpdate(ctx, itemID)  // FOR UPDATE lock
tx.UpdateItem(ctx, item.ID, item.Quantity-1)

經驗教訓

  • 「讀取後寫入」模式必須用 SELECT FOR UPDATE 或將 read 移入 tx,否則是 TOCTOU 問題

  • GDPR 合規操作(soft-delete + task)的原子性在 scale 下尤其重要,崩潰恢復依賴它

  • 扣資源與記錄日誌分開 commit 是常見反模式,排查時優先檢查這類配對操作

常見陷阱

  • CAS retry 模式(如 GiveGift)若 retry 前未確認前次操作是否真的失敗,可能重複消耗

  • tx 持有時間增加(將 read 移入 tx)有效能代價,需評估 lock contention

最佳實踐

  • 讀寫同一筆資料:read 必須在 tx 內(FOR UPDATE)

  • 狀態標記 + 後續任務:同一 tx

  • 扣資源 + 記錄日誌:同一 tx

相關概念

來源 Sessions

日期 Session 貢獻摘要

| 2026-03-17 | 10eef6a0-3a55-4d63-981c-6bc79aff1880 | 歸納出 Go 後端服務中三種常見的 transaction 邊界錯誤模式,並給出修正規則 |


本概念頁面由 Semi-Brain Wiki 系統自動維護

最後更新: 2026-03-17