前言
在开发中,经常需要进行多个操作,例如关联的数据更新、统计信息的计算等。当这些操作需要保证原子性时,需要使用事务处理,即一组多个操作要么全部成功,要么全部失败。Mongoose 是 Node.js 中操作 MongoDB 数据库的框架,提供了方便的事务处理方式,下面将介绍 Mongoose 中的事务处理。
Mongoose 中的事务处理
Mongoose 从 5.0 版本开始支持事务处理。具体实现使用 MongoDB 4.0 引入的事务处理。Mongoose 中使用事务处理的一个关键概念是会话(Session)。会话是在 Mongoose 和 MongoDB 之间的桥梁,它允许我们跨多个操作共享事务上下文。
Mongoose 中通过在 Schema 中使用 transaction: true
来开启事务处理。在事务中,我们尝试执行一组操作,并在这些操作之间维护原子性。如果这些操作中的任何一个失败,所有操作都会回滚,也就是之前执行过的所有操作都会撤销。最终结果是,所有事务内的操作要么都成功,要么都失败。
关于事务的概念可以看阮一峰老师的博客:数据库事务教程。
下面看一下 Mongoose 中的事务处理详细说明。
1. 开始事务
使用 Mongoose 进行事务处理,首先需要开启会话(Session)。我们可以通过调用 mongoose.startSession()
创建一个会话。如下所示:
const session = await mongoose.startSession();
创建完成后,我们可以在此会话上执行各种操作,这些操作可以共享事务上下文。接下来,我们调用 session.startTransaction()
开始事务。如下所示:
await session.startTransaction();
这样,我们就成功开启了一个 Mongoose 事务。
2. 向事务中添加操作
现在,我们已经成功开启了一个 Mongoose 事务,下面可以向其中添加一些操作了。在事务中执行任何操作都如同普通操作一样,只是在执行时需要传入会话对象。以更新一个用户数据为例,如下所示:
try { await userModel.findOneAndUpdate( { _id: userId }, { $set: { name: newName } }, { session } ).exec(); } catch (error) { console.log(`Transaction failed! Error: ${error.message}`); }
为了在事务中执行操作,我们需要将会话对象作为 options 参数传递给操作(即上例中的 session
)。
这些操作的类型可以是任何类型,包括插入、更新、删除等。
3. 发起提交或回滚
在事务完成时,我们需要提交或回滚事务。提交意味着所有操作都成功完成,而回滚意味着所有操作都失败了。Mongoose 中,分别使用 session.commitTransaction()
和 session.abortTransaction()
发起提交或回滚。
至此,我们已经完成了 Mongoose 中的事务处理,具体实现代码可以参考下面的示例。
示例代码
下面是一个简单的示例代码,展示了如何使用 Mongoose 进行事务处理。
const { connection, Schema } = require('mongoose'); (async () => { // 设置 MongoDB 连接 await connection.openUri('mongodb://localhost:27017/test'); // 定义数据模型 const UserSchema = new Schema({ name: String, age: Number }, { transaction: true // 开启事务 }); const User = connection.model('User', UserSchema); // 开启事务 const session = await connection.startSession(); await session.startTransaction(); try { // 添加一个用户 const newUser = new User({ name: 'Alice', age: 26 }); await newUser.save({ session }); // 更新用户信息 await User.updateOne( { _id: newUser._id }, { $set: { age: 27 } }, { session } ); // 提交事务 await session.commitTransaction(); console.log('Transaction committed!'); } catch (error) { // 回滚事务 await session.abortTransaction(); console.log(`Transaction failed! Error: ${error.message}`); } finally { // 关闭会话 session.endSession(); } // 关闭 MongoDB 连接 await connection.close(); })();
注意,由于 MongoDB 不支持跨两个或更多分片的事务,所以必须在同一分片上执行事务。如果要在多个分片之间执行事务,则必须将分片集合到副本集或分片集群中。
总结
Mongoose 从 5.0 版本开始支持事务处理。事务中的操作可以保证原子性,也可以统一提交或回滚操作。使用起来非常方便,它的应用范围广泛。在多个操作之间确保原子性时,事务处理非常有用。希望本篇文章对您有所启示。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6596839beb4cecbf2da53704