使用 transaction() 函数运行事务
import { Types } from "mongoose";
// 创建会话
const mongoSession = await this.app.mongoose.startSession();
// 开启事务
mongoSession.startTransaction();
try {
// SQL
await ctx.model.User.updateOne({
_id: Types.ObjectId("61c9aca30132f0005b956310"),
},
{
$set: {
nickname: "user01_updated",
},
},
{
session: mongoSession,
});
// SQL
await ctx.model.User.updateOne({
_id: Types.ObjectId("61caa13658a25700628e91d4"),
},
{
$set: {
nickname: "user02_updated",
// _id: 'user02_updated', // 错误的写法,_id是ObjectID,所以这条SQL语句不会被执行
},
},
{
session: mongoSession,
});
// do something...
// 假设这里业务逻辑出现异常,中止此会话中当前活动的事务
// await mongoSession.abortTransaction();
// 提交事务
await mongoSession.commitTransaction();
} catch (err) {
ctx.logger.error(err);
} finally {
// 在服务器上结束此会话
mongoSession.endSession();
}
使用 withTransaction() 函数运行事务
import { Types } from 'mongoose';
import assert = require('assert');
// 创建会话
const conn = ctx.app.mongoose.connection;
const mongoSession = await conn.startSession();
try {
// 执行事务
await mongoSession.withTransaction(async () => {
// SQL
const user = await ctx.model.User.findById({
_id: Types.ObjectId('61c9aca30132f0005b956310'),
}).session(mongoSession);
// 断言检查
assert.ok(user.$session());
// 更新nickname字段值
user.nickname = 'user01_updated';
const updateRes = await user.save();
// 成功则执行后续业务逻辑,失败则中断事务
if (updateRes) {
// do something...
} else {
await mongoSession.abortTransaction();
}
},
{
// 读策略
// 主节点,默认模式,读操作只在主节点,如果主节点不可用,报错或者抛出异常
readPreference: 'primary',
});
} catch (err) {
ctx.logger.error(err);
} finally {
// 在服务器上结束此会话
mongoSession.endSession();
}
参考资料
- https://mongoosejs.com/docs/transactions.html
- https://mongodb.github.io/node-mongodb-native/3.2/api/ClientSession.html#withTransaction