node.js - 如何使用 Mongoose 交易防止 "Given transaction number 1 does not match any in-progress transactions"?

标签 node.js mongodb mongoose transactions backend

我正在使用 Mongoose 访问我的数据库。我需要使用事务来进行原子插入更新。
我的交易在 95% 的情况下工作正常,但在 5% 的情况下显示错误:

“给定的交易号 1 不匹配任何正在进行的交易”

重现此错误非常困难,因此我真的很想了解它的来源以摆脱它。
我找不到关于这种行为的非常清楚的解释。

我曾尝试在各种功能上使用 async/await 关键字。不知道是手术不及时还是太早了。

这里是我使用的代码:

export const createMany = async function (req, res, next) {
  if (!isIterable(req.body)) {
    res.status(400).send('Wrong format of body')
    return
  }
  if (req.body.length === 0) {
    res.status(400).send('The body is well formed (an array) but empty')
    return
  }

  const session = await mongoose.startSession()
  session.startTransaction()
  try {
    const packageBundle = await Package.create(req.body, { session })
    const options = []
    for (const key in packageBundle) {
      if (Object.prototype.hasOwnProperty.call(packageBundle, key)) {
        options.push({
          updateOne: {
            filter: { _id: packageBundle[key].id },
            update: {
              $set: {
                custom_id_string: 'CAB' + packageBundle[key].custom_id.toLocaleString('en-US', {
                  minimumIntegerDigits: 14,
                  useGrouping: false
                })
              },
              upsert: true
            }
          }
        })
      }
    }
    await Package.bulkWrite(
      options,
      { session }
    )
    for (const key in packageBundle) {
      if (Object.prototype.hasOwnProperty.call(packageBundle, key)) {
        packageBundle[key].custom_id_string = 'CAB' + packageBundle[key].custom_id.toLocaleString('en-US', {
          minimumIntegerDigits: 14,
          useGrouping: false
        })
      }
    }
    res.status(201).json(packageBundle)
    await session.commitTransaction()
  } catch (error) {
    res.status(500).end()
    await session.abortTransaction()
    throw error
  } finally {
    session.endSession()
  }
}

我希望我的代码以原子方式添加到数据库中并更新入口包,没有不稳定的数据库状态。
这对于主要部分非常有效,但我需要确保不再显示此错误。

最佳答案

您应该使用 session.withTransaction()执行事务的辅助函数,如 mongoose documentation 中所述.这将负责启动、提交和重试事务,以防失败。

const session = await mongoose.startSession();
await session.withTransaction(async () => {
    // Your transaction methods
});

解释:
MongoDB 中的多文档事务相对较新,在某些情况下可能会有点不稳定,如 here 所述。 .当然,Mongoose 中也有报道 here .您的错误很可能是 TransientTransactionError由于提交事务时发生写冲突。
但是,这是来自 MongoDB 和 these 的已知和预期问题。 comments解释他们为什么决定这样的原因。此外,他们声称用户应该处理写冲突的情况并在发生这种情况时重试事务。
因此,查看您的代码,Package.create(...)方法似乎是触发错误的原因,因为此方法正在执行 save()对于数组中的每个文档( from mongoose docs )。
一个快速的解决方案可能是使用 Package.insertMany(...)而不是 create() , 自 Model.insertMany() “只向服务器发送一个操作,而不是每个文档一个”( from mongoose docs )。
但是,MongoDB 提供了一个辅助函数 session.withTransaction()这将负责启动和提交事务和 如果出现任何错误,请重试 , 自 release v3.2.1 .因此,这应该是您的 首选方式以更安全的方式处理交易;这当然是 available in Mongoose通过 Node.js API。

关于node.js - 如何使用 Mongoose 交易防止 "Given transaction number 1 does not match any in-progress transactions"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58487982/

相关文章:

node.js - 为什么我的 Sinon spy 函数在 promise then 子句中调用时不起作用?

javascript - Node.js 服务器中的同步 ajax

mongodb - 如何 $concat 对象数组中的字段?

javascript - Mongoose - TypeError : object is not a function

node.js - 使用bulkWrite 更新/更新插入不起作用

node.js - 数据库不是使用 Mongoose 和 Node.js 创建的

javascript - Node 在本地 get 请求中请求外部 API

php-node Node Express 找不到模块

java - @TextIndexed 在 Spring/Maven 中?

node.js - 等待函数,然后控制台结果