事务 1 已在 MongoDB 中提交

2024-04-24

我正在尝试使用事务来更新多个文档。

一种是加载表单文档 [await Sheet.save({ session });]

另一个是库存预订记录数组 [await Stock.bulkWrite()]。

    const session = await mongoose.startSession();

    session.startTransaction({
      readPreference: 'primary',
      readConcern: { level: 'local' },
      writeConcern: { w: 'majority' },
    });

    let sheetAfterSave: any = null;

    try {
      sheetAfterSave = await sheet.save({ session });
      records.forEach(async (el: any) => {
        let updatedStockRecord = await Stock.bulkWrite(
          [
            {
              updateOne: {
                filter: {
                  index: el.index,
                  product: el.product,
                  batchNo: el.batchNo,
                  agency,
                  totalQuantity: { $gte: el.loadingTotal },
                },
                update: {
                  $push: {
                    reservations: {
                      loadingSheetId: sheetAfterSave._id,
                      reservedCaseQuantity: el.loadingCaseCount,
                      reservedUnitQuantity: el.loadingUnitCount,
                      reservedTotalQuantity: el.loadingTotal,
                    },
                  },
                },
              },
            },
          ],
          {
            session: session,
          }
        );
      });
      await session.commitTransaction();
      session.endSession();
    } catch (error) {
      console.log(error);
      await session.abortTransaction();
      session.endSession();
      throw new Error(
        `Error occured while trying to create a new loading sheet. ${error}`
      );
    }

在此操作中,加载表文档保存在数据库中,但不保存在库存预订记录数组中。

它给出了错误

[distribution] MongoError: Transaction 1 has been committed.
[distribution]     at MessageStream.messageHandler (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/connection.js:263:20)
[distribution]     at MessageStream.emit (node:events:376:20)
[distribution]     at processIncomingData (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
[distribution]     at MessageStream._write (/app/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
[distribution]     at writeOrBuffer (node:internal/streams/writable:388:12)
[distribution]     at MessageStream.Writable.write (node:internal/streams/writable:333:10)
[distribution]     at TLSSocket.ondata (node:internal/streams/readable:716:22)
[distribution]     at TLSSocket.emit (node:events:376:20)
[distribution]     at addChunk (node:internal/streams/readable:305:12)
[distribution]     at readableAddChunk (node:internal/streams/readable:280:9)
[distribution]     at TLSSocket.Readable.push (node:internal/streams/readable:219:10)
[distribution]     at TLSWrap.onStreamRead (node:internal/stream_base_commons:192:23)
[distribution] [ERROR] 14:56:43 MongoError: Transaction 1 has been committed.

当我在这样的失败中使用会话时,必须回滚保存的文档,但这里没有发生这种情况。

我在这里错过了什么吗?感谢你的帮助

Cheers

你看到这段代码有什么问题吗?我试图在循环内创建一个动态错误,以确保如果循环内发生任何错误,所有事务都会回滚?循环外的动态错误会完美回滚所有事务,但不会回滚循环内的事务。

const session = await mongoose.startSession();

try {
  await session.withTransaction(
    async () => {
      sheetAfterSave = await sheet.save({ session });
      records.forEach(async (el: any) => {
        let updatedStockRecord = await Stock.bulkWrite(
          [
            {
              updateOne: {
                filter: {
                  index: el.index,
                  product: el.product,
                  batchNo: el.batchNo,
                  agency,
                  totalQuantity: { $gte: el.loadingTotal },
                },
                update: {
                  $push: {
                    reservations: {
                      loadingSheetId: sheetAfterSave._id,
                      reservedCaseQuantity: el.loadingCaseCount,
                      reservedUnitQuantity: el.loadingUnitCount,
                      reservedTotalQuantity: el.loadingTotal,
                    },
                  },
                },
              },
            },
          ],
          {
            session: session,
          }
        );
        console.log('******************');
        throw new Error('12/24/2020 ERROR INSIDE LOOP'); //  MongoError: Transaction 1 has been committed.
      });
      throw new Error('12/24/2020 ERROR OUTSIDE LOOP'); // All transactions are rolled back perfectly
    },
    {
      readPreference: 'primary',
      readConcern: { level: 'local' },
      writeConcern: { w: 'majority' },
    }
  );
} catch (error) {
  console.log('ERROR BLOCK', error);
  throw new Error(
    `Error occured while trying to create a new loading sheet. ${error}`
  );
} finally {
  session.endSession();
  await mongoose.connection.close();
  console.log('************ FINALLY *****************');
}

我能够解决这个问题。

问题不在于下面的代码

  await session.commitTransaction(); (success)
  session.endSession();              (failure)
} catch (error) {                    (entered)
  await session.abortTransaction();  (invoked)

但它是与 Records.forEach 循环一起使用的。

records.forEach(async (el: any) => {...});

在 foreach 内部,当抛出错误时,它不会被最外面的 try catch 块捕获,因为循环内部的内容与循环外部的代码处于不同的功能上下文中。

一旦我改变了循环.forEach to

for (const el of records) {}

它按预期工作。 发布答案,以防将来有人遇到同样的情况。感谢你们的支持 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

事务 1 已在 MongoDB 中提交 的相关文章

随机推荐