这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战
Sequelize 支持两种使用事务的方式:
- 非托管事务: 提交和回滚事务应该手动完成(通过调用适当的 Sequelize 方法)
- 托管事务: 如果抛出任何错误, 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();
});