MongoDB 原子操作(Atomic Operations)
在 MongoDB 中,原子操作(Atomic Operations)指的是不可分割的操作,即要么完整执行,要么完全不执行,不会被其他操作干扰。MongoDB 的单文档操作是原子性的,但多文档操作默认不具备原子性,需要事务来保证。
1. MongoDB 单文档原子操作
MongoDB 对单个文档的操作是原子的,即在更新、删除或插入某个文档时,不会发生部分修改或竞态条件。
示例:原子性更新
db.products.updateOne(
{ _id: 1 },
{ $inc: { stock: -1 } } // 库存减少 1
)
即使多个用户同时更新 _id:1 的 stock,MongoDB 也能确保每次更新是原子的,不会发生并发冲突。
2. 更新原子操作
MongoDB 提供了多种原子更新运算符,可在不覆盖整个文档的情况下更新字段。
① $inc(自增/自减)
db.users.updateOne(
{ username: "Alice" },
{ $inc: { points: 10 } } // 增加 10 积分
)
② $set(修改字段)
db.users.updateOne(
{ username: "Alice" },
{ $set: { status: "active" } } // 修改用户状态
)
③ $unset(删除字段)
db.users.updateOne(
{ username: "Alice" },
{ $unset: { tempField: "" } } // 删除 tempField 字段
)
④ $push(数组添加元素)
db.orders.updateOne(
{ _id: 101 },
{ $push: { items: "Keyboard" } }
)
⑤ $pull(数组删除元素)
db.orders.updateOne(
{ _id: 101 },
{ $pull: { items: "Mouse" } }
)
3. FindAndModify 原子性操作
findAndModify 是一个原子性操作,它可以查找并更新或删除文档,同时返回更新前或更新后的文档。
示例:原子性递增
db.counters.findAndModify({
query: { _id: "orderId" },
update: { $inc: { seq: 1 } },
new: true
})
这个操作原子性地递增 seq 并返回新值,可用于实现自增 ID。
4. 多文档操作的原子性
MongoDB 默认不保证多文档更新的原子性,但可以通过事务(Transactions)实现。
示例:使用事务保证原子性
const session = db.getMongo().startSession();
session.startTransaction();
try {
session.getDatabase("test").collection("accounts").updateOne(
{ username: "Alice" },
{ $inc: { balance: -100 } }
);
session.getDatabase("test").collection("accounts").updateOne(
{ username: "Bob" },
{ $inc: { balance: 100 } }
);
session.commitTransaction();
} catch (error) {
session.abortTransaction();
}
session.endSession();
⚠ 注意:事务仅适用于 MongoDB 4.0+ 的副本集,MongoDB 4.2+ 才支持分片事务。
5. 原子操作的应用场景
| 场景 | 解决方案 |
|---|---|
| 计数器自增 | $inc |
| 乐观锁 | $set + version 字段 |
| 购物车更新 | $push / $pull |
| 并发更新用户数据 | findAndModify |
| 多表更新事务 | 事务(Transactions) |
6. 总结
- MongoDB 的单文档操作是原子的,不会发生部分更新。
- 使用
$inc、$set、$push、$pull等更新操作可原子性地修改数据。 findAndModify可确保查找 + 更新的原子性。- 多文档更新不具备原子性,需要使用事务(Transactions)确保一致性。
更多详细内容请关注其他相关文章!