前言
MongoDB 是一款非关系型数据库,它提供了很多强大的功能,比如高效的查询、存储大量数据、自动分片等等。在使用 MongoDB 时,我们可能需要对多个文档进行操作,而这些操作需要保证数据的一致性,这就需要用到事务机制和锁机制。
事务机制
事务(Transaction)是指一组数据库操作,这组操作要么全部执行,要么全部不执行,这保证了数据库的数据完整性和一致性。在 MongoDB 中,事务机制一般用于多个文档的操作,比如在一个文档中新增数据的同时也需要更新另一个文档的数据。
MongoDB 中的事务机制是基于集合的,也就是在一个集合中执行多个操作。MongoDB 的事务机制分为单文档事务和多文档事务,分别适用于单个数据文档和多个数据文档的场景。
单文档事务
单文档事务指的是在一个文档中进行多个操作,这些操作要么全部完成,要么全部不完成。MongoDB 中的单文档事务只支持以下操作:
- $set
- $unset
- $rename
- $inc
- $mul
- $min
- $max
- $currentDate
- $addToSet
- $push
- $pull
以下是一个示例代码:
// www.javascriptcn.com code example
session = db.getMongo().startSession();
session.startTransaction();
try {
const coll = session.getDatabase("myDatabase").myCollection;
await coll.updateOne({ _id: 1 }, { $set: { status: "processing" } });
await coll.updateOne({ _id: 2 }, { $set: { status: "processing" } });
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
console.log(error);
}在这个示例中,我们通过 session 对象启动了一个事务,然后依次执行了两个文档的更新操作,最后通过 commitTransaction 提交事务或者通过 abortTransaction 回滚事务。
多文档事务
多文档事务指的是在多个文档中进行多个操作,这些操作要么全部完成,要么全部不完成。MongoDB 中的多文档事务需要使用到两个集合间的关系,可以使用 lookup 或者 aggregate 进行关联查询和聚合操作。
以下是一个示例代码:
// www.javascriptcn.com code example
session = db.getMongo().startSession();
session.startTransaction();
try {
const orders = session.getDatabase("store").orders;
const customers = session.getDatabase("store").customers;
const result = await orders.aggregate([{ $lookup: { from: "customers", localField: "cust_id", foreignField: "_id", as: "customer_info" } }, { $match: { total_price: { $gt: 100 } } }, { $out: "result" } ]).next();
await session.commitTransaction();
console.log(result);
} catch (error) {
await session.abortTransaction();
console.log(error);
}在这个示例中,我们查询了 store 数据库中的 orders 集合,并关联了 customers 集合,然后根据 total_price 大于 100 对数据进行筛选并将结果输出到 result 集合中,最后通过 commitTransaction 提交事务或者通过 abortTransaction 回滚事务。
锁机制
在 MongoDB 中,锁机制用于保证数据的一致性和避免多个线程对同一份数据进行操作。MongoDB 中的锁机制分为共享锁和独占锁。
- 共享锁(Shared Lock):所有的查询操作都会获得共享锁,共享锁不会阻塞其他的共享锁,但是会阻塞独占锁。
- 独占锁(Exclusive Lock):所有的写入操作都会获得独占锁,独占锁会阻塞其他的共享锁和独占锁。
MongoDB 中的锁机制是自动管理的,一般情况下不需要手动控制。但是在一些复杂的操作中,可能需要手动控制锁机制,比如需要逐步获得和释放锁,或者需要控制锁的持续时间。
以下是一个示例代码:
const session = db.getMongo().startSession();
await session.withTransaction(async () => {
const coll = session.getDatabase("myDatabase").myCollection;
await coll.updateOne({ _id: 1 }, { $set: { status: "processing" } }, { session, upsert: true });
// 手动控制锁机制,先获得共享锁,然后再获得独占锁
await coll.findOne({ _id: 1 }, { session, readConcern: { level: "majority" }, maxTimeMS: 5000, collation: { locale: "en_US", strength: 1 } });
await coll.updateOne({ _id: 1 }, { $set: { status: "done" } }, { session, upsert: true });
});在这个示例中,我们使用 withTransaction 方法开启一个事务,然后逐步获得并释放锁。首先使用 $set 操作更新了 _id 为 1 的文档,然后通过 findOne 方法获得了一个共享锁,该方法会等待 5 秒,然后再使用 $set 操作更新 _id 为 1 的文档,这时会获得一个独占锁。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d02d07e46428fe9ece1433