全书目录

第十九篇:MongoDB 完全指南 —— 弹性档案仓宇宙

第十一章:事务认知 —— 一袋一袋改,还是多袋联动改

1 分钟 331 字 第 362 / 962 个阅读单元

MongoDB 最容易被误解的地方之一,就是事务。

先记住一句最重要的话:

单文档操作是原子的。

也就是说,如果你的业务能被设计成“一个关键动作只改一份档案袋”,MongoDB 会非常自然。

比如更新订单文档中的状态、支付时间、物流号:

javascript
db.orders.updateOne(
  { orderNo: "ORD-9001" },
  {
    $set: {
      status: "shipped",
      shippedAt: new Date(),
      trackingNo: "SF12345678"
    }
  }
)

这一次更新,对这份订单文档来说就是原子的。

那什么时候需要事务?

  • 同时改多份文档
  • 同时改多个集合
  • 中间任何一步失败都必须整体回滚

例如转账:

javascript
const session = db.getMongo().startSession()

session.withTransaction(() => {
  const accounts = session.getDatabase("bank_archive").accounts

  accounts.updateOne(
    { _id: "A", balance: { $gte: 100 } },
    { $inc: { balance: -100 } }
  )

  accounts.updateOne(
    { _id: "B" },
    { $inc: { balance: 100 } }
  )
})

但这里的关键认知不是“MongoDB 也能做事务”,而是:

有事务,不代表应该先靠事务救设计。

更推荐的思路是:

  1. 先把模型设计成尽量利用单文档原子性
  2. 只有确实跨文档一致性不可避免时,再启用事务

在弹性档案仓里,最优方案通常是:
尽量让一个业务动作,落在尽量少的档案袋上。