返回首页

多阶段事务:在 DBMS 中实现容错操作

本文讲解了使用幂等操作在 DBMS 中实现多阶段事务以确保容错性。锁定、执行和解锁阶段结合 MongoDB 的代码示例予以考虑。

如何实现容错事务:逐步详解
Advertisement 728x90

构建可靠事务:幂等操作实战指南

多阶段事务通过幂等操作和状态日志,确保故障时数据完整性。这种方法适用于任何数据库,包括 MongoDB,能有效防止断电或系统崩溃导致的数据丢失。

多阶段事务工作原理

事务拆分为顺序阶段,每阶段记录在独立的 TRANSACTIONS 表中。主要状态包括:

  • blocking — 锁定账户,防止并发操作。
  • save_balance — 在日志中快照原始余额。
  • main — 执行核心资金转账。
  • unlock — 完成后台解锁账户。
  • finished — 成功事务的最终状态。

幂等性确保故障后重复执行阶段不会破坏数据。例如,A := B + 1 是幂等的,而 A := A + 1 不是——但可拆分为两个幂等步骤。

Google AdInline article slot

带代码示例的实现步骤

假设从 Assange 账户转账 250 元给 Agent Y。ACCOUNTS 表初始数据:

| ID | NAME | BALANCE | TR_ID |

|----|----------|---------|-------|

Google AdInline article slot

| 34 | Assange | 300 | null |

| 78 | Agent Y | 7 | null |

1. 锁定账户 (STATUS='blocking')

先创建 TRANSACTIONS 记录:

Google AdInline article slot

| ID | FROM_ID | TO_ID | AMOUNT | FROM_BALANCE | TO_BALANCE | STATUS |

|----|---------|-------|--------|--------------|------------|----------|

| 172| 34 | 78 | 250 | null | null | blocking |

锁定使用原子命令,例如在 MongoDB 中:

db.accounts.updateOne(
  { ID: 34, TR_ID: null },
  { $set: { TR_ID: 172 } }
);

若无文档更新,则锁定失败——重试或中止。提前排序 ID 避免死锁。

2. 快照余额 (STATUS='save_balance')

锁定后,将原始余额复制到 TRANSACTIONS——设计上即幂等:

db.transactions.updateOne(
  { ID: 172 },
  { $set: { FROM_BALANCE: 300, TO_BALANCE: 7, STATUS: 'save_balance' } }
);

3. 执行转账 (STATUS='main')

核心操作利用保存的余额实现幂等:

db.accounts.updateOne(
  { ID: 34, TR_ID: 172 },
  { $set: { BALANCE: 50 } } // 300 - 250
);

db.accounts.updateOne(
  { ID: 78, TR_ID: 172 },
  { $set: { BALANCE: 257 } } // 7 + 250
);

变更生效后,才更新状态为 'unlock'。

4. 解锁并完成 (STATUS='unlock')

通过 TR_ID 检查释放锁:

db.accounts.updateOne(
  { ID: 34, TR_ID: 172 },
  { $set: { TR_ID: null } }
);

双账户解锁后,设置状态为 'finished'。

优势与局限

核心优势:

  • 容错性:任何故障均可恢复,无数据丢失。
  • 幂等性:安全重试操作,对分布式系统至关重要。
  • 通用性:适用于各类数据库,不限于 MongoDB。
  • 一致性:每个阶段均保障数据完整。
  • 性能:额外日志可能略微降低速度。

缺点包括复杂度增加和日志开销。对于金融应用或关键系统,价值远超成本。

开发者Tips

  • 利用数据库原子操作实现锁和更新。
  • 为失败锁构建重试逻辑。
  • 测试崩溃场景,如进程突发终止。
  • 排序 ID 降低死锁风险。

此方案提供 2PC 级可靠性,同时保留 NoSQL 灵活性。

— Editorial Team

Advertisement 728x90

继续阅读