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

Mongoose中session.abortTransaction无法回滚事务问题求助

Mongoose事务调用abortTransaction()后未回滚操作的问题排查与解决

我刚看了你的代码,问题出在Mongoose事务的session传递方式上——你调用create方法时的参数格式错误,导致这些数据库操作根本没加入到事务上下文里,所以abortTransaction()自然不会回滚它们。

问题根源

Mongoose的Model.create()方法签名是create(docs, options),第二个参数是配置对象(用来传递session、timestamps等选项),而不是你现在写的第三个参数。你当前的写法create([...], null, session)会把null当成配置选项,session被当成了回调函数(但你用的是async/await,回调不会触发),这就导致这些创建操作完全脱离了事务session,变成了独立的非事务操作,所以即使调用abortTransaction(),这些操作也不会被回滚。

同样,你的findOne和findById调用也存在类似的参数传递问题,虽然查询操作本身不会修改数据,但为了保证事务上下文的一致性,也应该用正确的方式传递session。

修正后的代码

下面是调整了session传递方式的核心代码片段:

export const signUp = async (req, res) => { 
  const { email, password, fullname } = req.body; 
  // Init session 
  const session = await mongoose.startSession(); 
  // Begin transaction 
  session.startTransaction(); 
  try { 
    // Check if user exist - 修正session传递方式
    const dbUser = await UserModel.findOne({ email }, { session }); 
    if (dbUser) return res.status(409).json({ message: "User already exists" }); 

    // Create tenant - 修正create的参数
    const tenantResult = await TenantModel.create([{ createdAt: new Date() }], { session }); 

    // Get admin role - 修正session传递方式
    const roleResult = await RoleModel.findById('626db17b8645717d657fc4c8', { session }); 

    //Hash password 
    const hashedPassword = await bcrypt.hash(password, 12); 

    // Store user in db - 修正create的参数
    const userResult = await UserModel.create([ 
      { email: email, password: hashedPassword, fullname: fullname, tenant: tenantResult[0], role: roleResult } 
    ], { session }); 

    throw new Error("Error message"); 

    if (userResult){ 
      // Create currency - 修正create的参数
      await CurrencyModel.create([ 
        { 
          name: 'Dollar', 
          createdAt: new Date(), 
          symbol: '$', 
          isoCode: 'USD', 
          default: true, 
          userRole: 'setting-list', 
          createdBy: userResult[0], 
        } 
      ], { session }); 
    } 

    // Generate token using jwt, secret, and user data 
    const token = jwt.sign( 
      { email: userResult[0].email, id: userResult[0]._id }, 
      secret, 
      { expiresIn: "24h" } 
    ); 

    // Send welcome email to registered user 
    await sendWelcomeEmail(userResult[0].email, userResult[0].fullname, `Welcome ${userResult[0].fullname} - light-speed.dev`, 'welcome-email.html'); 

    //Commit transaction 
    await session.commitTransaction(); 
    return res.status(201).json({ userResult, token }); 
  } catch (error) { 
    // Abort transaction if one of these request throw error 
    await session.abortTransaction(); 
    console.log(error); 
    return res.status(400).json({ message: 'Something went wrong!' }); 
  } finally { 
    // close session 
    session.endSession(); 
  } 
};

额外注意事项

  • 确保所有和事务相关的数据库操作都明确传递了{ session }选项,包括查询、创建、更新、删除等操作,否则该操作会脱离事务上下文。
  • 在事务中尽量统一使用async/await,避免混用回调函数,否则可能导致session状态不一致。
  • 确认你的Mongoose版本支持事务功能(需要MongoDB 4.0+,Mongoose 5.2+),并且集合是分片集群或者副本集(单节点MongoDB默认不支持事务)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:22:38