Node.js 7如何使用异步/等待的sequelize事务?

qiu*_*jie 52 transactions sequelize.js

Node.js 7及更高版本已经支持async/await语法.我应该如何使用sequelize事务的async/await?

小智 121

let transaction;    

try {
  // get transaction
  transaction = await sequelize.transaction();

  // step 1
  await Model.destroy({where: {id}, transaction});

  // step 2
  await Model.create({}, {transaction});

  // step 3
  await Model.update({}, {where: {id}, transaction });

  // commit
  await transaction.commit();

} catch (err) {
  // Rollback transaction only if the transaction object is defined
  if (transaction) await transaction.rollback();
}
Run Code Online (Sandbox Code Playgroud)

  • @Pier,await等待sequelize.transaction(),然后得到它的结果.这不是承诺,而是承诺的结果. (5认同)
  • 如果`transaction = await sequelize.transaction();`失败怎么办?然后`transaction.rollback()`会抛出一个错误.我们是否需要检查catch块中的事务是否可以使用.rollback? (3认同)
  • 在我的情况下,它不起作用,直到我将交易作为键:值传递。例如,在上面的解决方案中,{transaction:transaction} 正在工作。我使用的是sequelize版本5.19.2 (2认同)

kos*_*nix 37

接受的答案是"非托管交易",这需要调用commitrollback明确.对于任何想要"托管交易"的人来说,这就是它的样子:

try {
    // Result is whatever you returned inside the transaction
    let result = await sequelize.transaction( async (t) => {
        // step 1
        await Model.destroy({where: {id: id}, transaction: t});

        // step 2
        return await Model.create({}, {transaction: t});
    });

    // In this case, an instance of Model
    console.log(result);
} catch (err) {
    // Rollback transaction if any errors were encountered
    console.log(err);
}
Run Code Online (Sandbox Code Playgroud)

要回滚,只需在事务函数中抛出一个错误:

try {
    // Result is whatever you returned inside the transaction
    let result = await sequelize.transaction( async (t) => {
        // step 1
        await Model.destroy({where: {id:id}, transaction: t});

        // Cause rollback
        if( false ){
            throw new Error('Rollback initiated');
        }

        // step 2
        return await Model.create({}, {transaction: t});
    });

    // In this case, an instance of Model
    console.log(result);
} catch (err) {
    // Rollback transaction if any errors were encountered
    console.log(err);
}
Run Code Online (Sandbox Code Playgroud)

如果任何在事务块内引发错误的代码,则会自动触发回滚.


rli*_*lib 5

user7403683给出的答案描述了用于非托管事务的异步/等待方式(http://docs.sequelizejs.com/manual/tutorial/transactions.html#unmanaged-transaction-then-callback-

异步/等待样式的托管事务可能如下所示:

await sequelize.transaction( async t=>{
  const user = User.create( { name: "Alex", pwd: "2dwe3dcd" }, { transaction: t} )
  const group = Group.findOne( { name: "Admins", transaction: t} )
  // etc.
})
Run Code Online (Sandbox Code Playgroud)

如果发生错误,事务将自动回滚。


Tho*_*Tho 5

如果启用了 CLS,Sequelize 可以使用它来保留您的事务对象并自动将其传递给continuation-passing循环内的所有查询。

设置:

import { Sequelize } from "sequelize";
import { createNamespace } from "cls-hooked"; // npm i cls-hooked

const cls = createNamespace("transaction-namespace"); // any string
Sequelize.useCLS(cls);

const sequelize = new Sequelize(...);
Run Code Online (Sandbox Code Playgroud)

用法:

const removeUser = async (id) => {
    await sequelize.transaction(async () => { // no need `async (tx)`
        await removeUserClasses(id);
        await User.destroy({ where: { id } }); // will auto receive `tx`
    });
}

const removeUserClasses = async (userId) => {
    await UserClass.destroy({ where: { userId } }); // also receive the same transaction object as this function was called inside `sequelize.transaction()`
    await somethingElse(); // all queries inside this function also receive `tx`
}
Run Code Online (Sandbox Code Playgroud)

这个怎么运作?

从 Sequelize 源代码: github.com/sequelize

检查并将交易保存到 CLS

if (useCLS && this.sequelize.constructor._cls) {
    this.sequelize.constructor._cls.set('transaction', this);
}
Run Code Online (Sandbox Code Playgroud)

从 CLS 检索交易并设置为选项

if (options.transaction === undefined && Sequelize._cls) {
    options.transaction = Sequelize._cls.get('transaction');
}
Run Code Online (Sandbox Code Playgroud)

阅读更多:

  1. Sequelize:自动将事务传递给所有查询
  2. CLS 上钩了
  3. 异步钩子