NodeJS的sequelize的事务

1,571 阅读2分钟

这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

Sequelize 支持两种使用事务的方式:

  1. 非托管事务:  提交和回滚事务应该手动完成(通过调用适当的 Sequelize 方法)
  2. 托管事务: 如果抛出任何错误, Sequelize 将会自动回滚事务, 否则将提交事务, 另外,如果启用了CLS(连续本地存储), 则事务回调中的所有查询将自动接收事务对象

非托管事务

手动提交和回滚事务

// 首先,我们开始一个事务并将其保存到变量中
const t = await sequelize.transaction();

try {

  // 然后,我们进行一些调用以将此事务作为参数传递:

  const user = await User.create({
    firstName: '张',
    lastName: '三'
  }, { transaction: t });

  await user.addSibling({
    firstName: '李',
    lastName: '四'
  }, { transaction: t });

  // 如果执行到此行,且没有引发任何错误.
  // 我们提交事务.
  await t.commit();

} catch (error) {

  // 如果执行到达此行,则抛出错误.
  // 我们回滚事务.
  await t.rollback();

}

托管事务

托管事务会自动处理提交或回滚事务. 将会通过回调传递给 sequelize.transaction 来启动托管事务, 回调可以是 async的异步.

  • Sequelize 将会自动开始事务并获得事务对象 t

  • 然后 Sequelize 将执行你提供的回调, 并在其中传递对象 t

  • 如果回调抛出错误, Sequelize 将会自动回滚事务

  • 如果回调成功, Sequelize 将会自动提交事务

  • sequelize.transaction 调用会解决问题:

    • 解决回调的判断
    • 如果回调引发错误, 则拒绝并抛出错误

注意 t.commit() 和 t.rollback() 没有被直接调用

try {

  const result = await sequelize.transaction(async (t) => {

    const user = await User.create({
        firstName: '张',
        lastName: '三'
    }, { transaction: t });

    await user.setShooter({
        firstName: '李',
        lastName: '四'
    }, { transaction: t });

    return user;

  });

  // 如果执行到此行,则表示事务已成功提交,`result`是事务返回的结果
  // `result` 就是从事务回调中返回的结果(在这种情况下为 `user`)

} catch (error) {

  // 如果执行到此,则发生错误.
  // 该事务已由 Sequelize 自动回滚!

}

抛出错误以回滚

使用自动托管事务时,不用手动提交或回滚事务. 如果所有查询都成功, 但是想回滚事务, 自己自由地抛出一个错误:

await sequelize.transaction(async t => {
  const user = await User.create({
    firstName: '李',
    lastName: '四'
  }, { transaction: t });

  // 查询成功,但是想决定回滚
  throw new Error();
});