Mongoose withTransaction 仅部分执行

Posted

技术标签:

【中文标题】Mongoose withTransaction 仅部分执行【英文标题】:Mongoose withTransaction only partially executes 【发布时间】:2020-12-27 11:00:22 【问题描述】:

Mongoose 的 session.withTransaction 助手只执行第一次写入。代码如下:

const session = await mongoose.startSession();

await session.withTransaction(async () => 
  const member = await Member.create([
    name: 'John Doe'
    email: 'johndoe@example.com',
  ],  session );

  await User.updateOne( _id: req.user.id ,  member: member._id ,  session );
);

此代码在数据库中创建一个新成员,但不更新用户。事务的意义不是只有在每个操作都成功的情况下才会进行吗?我究竟做错了什么;还是 Mongoose 无法做到这一点?

猫鼬:5.9.26, Node.js:14.9.0

【问题讨论】:

req.user.id可能是字符串,users集合中_id字段是什么类型? @Joe 也是一个字符串,我已经检查过了,这不是问题。 尝试给 updateOne 调用一个回调来记录更新的文档,这样你就可以看到它匹配的内容。 @Joe hmmm...我遇到了一个错误,MongoError: Transaction 1 has been committed. 在 withTransaction 代码中发现了这条注释:“* 重要提示:此方法要求用户返回一个 Promise,所有不返回 Promise 的 lambdas 都会导致未定义的行为。” 【参考方案1】:

检查是否使用您将基于事务的模型启动会话有帮助:

const session = await Member.startSession();

【讨论】:

【参考方案2】:

错误来自https://github.com/mongodb/mongo/blob/11c68393df88a6f1ea4855e6ac15e54ca9f9d976/src/mongo/db/transaction_participant.cpp#L1712

// Cannot change committed transaction but allow retrying commitTransaction command.
uassert(ErrorCodes::TransactionCommitted,
        str::stream() << "Transaction " << requestTxnNumber << " has been committed.",
        cmdName == "commitTransaction" || !o().txnState.isCommitted());

显然您正在尝试两次提交事务。确保您不重复使用它。始终结束会话:

const session = await mongoose.startSession();

try  
    await session.withTransaction(async () => ...)
 finally 
    await session.endSession()

【讨论】:

【参考方案3】:

你有没有试过这样写

session :session 

【讨论】:

猜猜,这不会有什么不同。 session 应该是对象文字速记语法。 在猫鼬中有所不同我都试过了, session 不起作用。【参考方案4】:

确保您已设置副本,事务需要副本才能工作。

【讨论】:

以上是关于Mongoose withTransaction 仅部分执行的主要内容,如果未能解决你的问题,请参考以下文章

使用 JPA.withTransaction 的测试 Actor(java.lang.IllegalStateException:EntityManager 在测试时关闭)

Grails,使用 withTransaction 插入大量数据会导致 OutOfMemoryError

Django 嵌套事务 - “with transaction.atomic()”

升级 Play 到 2.4,Slick 到 3.1.1,值 withTransaction 不是 play.api.db.slick.Database 的成员

mysql上的Grails事务setSavePoint方法导致异常

开启事务的两种方法