基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

MongoDB 支持哪些原子操作?

知识点图片

MongoDB 对原子操作的支持主要分为三个层面:单文档原子性(核心机制)原子操作符以及多文档事务(ACID)

以下是详细的分类说明:

1. 单文档原子性 (Single Document Atomicity)

这是 MongoDB 最基础也是最重要的特性。在 MongoDB 中,针对单个文档(Document)的所有写操作(insert, update, delete)都是原子的。

即使一个 update 操作需要修改该文档内的多个字段(例如同时修改嵌套数组和顶层字段),这个操作要么全部成功,要么全部失败,不会出现只修改了一半的情况。

2. 原子更新操作符 (Atomic Update Operators)

为了在修改单文档时实现复杂的逻辑(如计数、数组操作),MongoDB 提供了一系列原子操作符。这些操作符在并发环境下非常有用,避免了“读取-修改-写入”带来的竞态条件。

  • 字段修改类:

    • $set: 设置字段的值。
    • $unset: 删除字段。
    • $inc: 对数值字段进行原子增减(常用于计数器,无需先读后写)。
    • $mul: 将字段值乘以指定数值。
    • $rename: 重命名字段。
    • $currentDate: 设置字段为当前时间。
  • 数组修改类:

    • $push: 向数组追加元素。
    • $pop: 移除数组头部或尾部的元素。
    • $pull: 移除数组中匹配特定条件的元素。
    • $addToSet: 仅当元素不存在时才向数组添加(去重添加)。
    • $pullAll: 移除数组中所有指定的元素。
  • 位运算类:

    • $bit: 对整型字段进行位运算(AND, OR, XOR)。

3. findAndModify 类操作 (原子读写)

这是一个非常强大的功能,它允许你在一个原子操作中完成“查询”和“更新/删除”,并返回更新前或更新后的文档。这对于实现任务队列、分布式锁或序列生成器至关重要。

  • findOneAndUpdate(): 查找文档,修改它,并返回(修改前或修改后的)文档。
  • findOneAndReplace(): 查找文档,完全替换它,并返回文档。
  • findOneAndDelete(): 查找文档,删除它,并返回被删除的文档。

4. 多文档事务 (Multi-Document Transactions)

MongoDB 4.0 开始(副本集)和 4.2(分片集群),MongoDB 支持跨多个文档、多个集合甚至多个数据库的 ACID 事务

  • 这意味着你可以像在关系型数据库(如 MySQL)中一样,使用 startTransactioncommitTransactionabortTransaction
  • 在事务块内的所有操作,要么全部提交,要么全部回滚,对外表现为原子性。
  • 注意:虽然支持,但 MongoDB 官方建议优先通过合理的数据建模(如嵌入式文档)利用单文档原子性,因为多文档事务会有一定的性能开销。

5. 批量操作 (Bulk Write Operations)

使用 bulkWrite() 可以执行一组写操作。

  • 有序 (Ordered - 默认): 按顺序执行。如果中间某个操作失败,后续操作停止。虽然整体不是原子的(除非放在事务中),但每个单独的操作是原子的。
  • 无序 (Unordered): 并行执行。如果某个操作失败,其他操作继续。

6. 并发控制模式 (CAS - Compare And Swap)

虽然这不是一个具体的命令,但利用单文档原子性,MongoDB 经常被用来实现乐观锁(Optimistic Locking):

javascript
// 只有当 version 等于读取到的值时才更新,实现原子性的“检查并设置”
db.collection.updateOne(
   { _id: 1, version: 5 },
   { 
     $set: { status: "active" }, 
     $inc: { version: 1 } 
   }
)

总结

操作层级 描述 典型场景
单文档 原生支持,默认原子性 绝大多数日常 CRUD 操作
字段/数组 $inc, $push 等操作符 计数器、标签管理、点赞数
读写混合 findAndModify 任务队列领取、状态流转
多文档 事务 (Transactions) 银行转账、订单库存扣减 (跨集合)
00:00
00:00