You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose多集合事务实现方法及常见报错解决方案

Mongoose事务问题解答

问题1:操作未随事务回滚的解决方案

你所有需要纳入原子事务的数据库操作,都必须显式绑定当前创建的事务会话,未传入session参数的操作会走默认独立会话,不会被事务管控,自然不会回滚。修改后的业务代码如下:

const registerCustomer = async (req, res) => {
    const session = await mongoose.startSession();
    session.startTransaction();
    try {
        // 给更新操作传入session参数
        await CustomerRegistrationCode.findByIdAndUpdate(req.body._id, { used: true }, { session: session });
        // 给创建操作传入session参数
        const customer = await Customer.create([{ firstName: req.body.firstName }], { session: session });
        await session.commitTransaction();
        session.endSession();
        res.status(200).json(customer);
    } catch (error) {
        console.error('abort transaction');
        await session.abortTransaction();
        session.endSession();
        res.status(500).json(error);
        throw error;
    }
}

注意create方法传入session时,第一个参数需要是数组格式,不同Mongoose版本兼容该写法。

问题2:官方示例报错的解决方案

报错Transaction numbers are only allowed on a replica set member or mongos的原因是MongoDB事务仅支持副本集或者分片集群运行环境,本地默认启动的单节点独立模式不支持事务功能。你可以按照以下步骤快速启动本地单节点副本集:

  • 关闭本地正在运行的MongoDB进程
  • 执行命令以副本集模式启动Mongo:mongod --port 27017 --dbpath /你的数据库存储路径 --replSet rs0
  • 新开终端进入Mongo shell,执行副本集初始化命令:rs.initiate()
    等待10-30秒初始化完成后,即可正常运行事务相关代码。

可运行最小完整示例

const mongoose = require('mongoose');
const assert = require('assert');

const debugMongo = async () => {
  // 连接数据库,确保已经启动本地单节点副本集
  await mongoose.connect("mongodb://localhost:27017/mongotest");
  
  // 定义测试模型
  const Customer = mongoose.model('Customer', new mongoose.Schema({ name: String }));
  const CustomerRegistrationCode = mongoose.model('CustomerRegistrationCode', new mongoose.Schema({ code: String, used: Boolean }));

  // 提前插入一条测试用的注册码
  await CustomerRegistrationCode.create({ code: 'test123', used: false });
  const testCode = await CustomerRegistrationCode.findOne({ code: 'test123' });

  // 开启事务
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    // 绑定session执行操作
    await CustomerRegistrationCode.findByIdAndUpdate(testCode._id, { used: true }, { session });
    // 这里故意写错字段触发错误,测试回滚
    await Customer.create([{ wrongField: 'Test' }], { session });

    await session.commitTransaction();
  } catch (error) {
    console.log('事务回滚触发');
    await session.abortTransaction();
  } finally {
    session.endSession();
  }

  // 验证回滚结果:used字段仍然是false
  const checkCode = await CustomerRegistrationCode.findById(testCode._id);
  assert.equal(checkCode.used, false);
  console.log('事务回滚验证通过');

  await mongoose.disconnect();
}

debugMongo();

内容的提问来源于stack exchange,提问作者swftowu69

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:39:03