Sequelize事务回滚到特定保存点。

3

我的项目中使用托管交易,我有一个需求需要在出现失败情况时回滚到保存点,并最终提交事务。

例如,我想要创建一个 Event 并尝试运行一个action。如果action失败,我想回滚任何在此期间发生的数据库活动,但保留 Event 记录并随后使用结果更新它。

const transaction = await sequelize.transaction();

const event = await Event.create({ ... }, { transaction });

// I want to mark the savepoint here

try {
  const action = await runAction(transaction);
  event.status = 'success';
  event.action_id = action.id;
} catch (err) {
  // This is where I want to rollback any changes since the savepoint
  event.status = 'failure';
  event.failure_message = err.message;
}

await event.save({ transaction });
await transaction.commit();

据我的理解,我应该能够通过创建一个新的事务来实现这一点,有效地标记保存点:
const transaction = await sequelize.transaction();

const event = await Event.create({ ... }, { transaction });

const savepoint = await sequelize.transaction({ transaction });

try {
  const action = await runAction(savepoint);
  ...
} catch (err) {
  await savepoint.rollback();
  ...
}

await event.save({ transaction });
await transaction.commit();

然而这并不起作用,而且在“runAction”中使用事务的所有操作仍然被提交。有没有办法实现这一点?
1个回答

3

我发现在runAction中调用了findOrCreate。当在选项中提供事务时,Sequelize会在findOrCreate内创建保存点。

当创建一个新事务并在选项中提供事务时,它会自动创建一个保存点(如此处所示)。这个保存点被赋予一个ID(以其在父级上的索引为基础),并执行数据库查询在事务中设置保存点。因此,当我运行sequelize.transaction({ transaction });时,它会创建一个名为“transaction-id-1”的保存点。后来,当findOrCreate被调用并提供了“savepoint”事务时,它会创建一个名称相同的保存点“transaction-id-1”,有效地覆盖了之前的保存点。

因此,在runAction中应该传递父事务而不是savepoint

const transaction = await sequelize.transaction();

const event = await Event.create({ ... }, { transaction });

const savepoint = await sequelize.transaction({ transaction });

try {
  // Pass parent transaction, rather savepoint transaction
  const action = await runAction(transaction);
  ...
} catch (err) {
  await savepoint.rollback();
  ...
}

await event.save({ transaction });
await transaction.commit();

你如何命名保存点?我尝试用这种方式创建保存点,但似乎不起作用。在你的代码中,“savepoint”对象到底是什么?这是一个单独的事务还是实际的mysql保存点? - Joseph Astrahan
你现在使用的sequelize.transaction({transaction})方式并不是使用保存点,而是创建了一个新的事务。如果想要使用保存点,你需要在示例中写成{transaction:transaction}。希望这能帮助到其他人!传递给transaction的选项对象中关键字必须为“transaction”,才能使用保存点。同时请注意,只有支持保存点的系统才能使用它,例如MySQL。 - Joseph Astrahan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接