【问题标题】:Node.js 7 how to use sequelize transaction with async / await?Node.js 7 如何使用异步/等待的续集事务?
【发布时间】:2017-08-09 18:28:35
【问题描述】:

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

【问题讨论】:

    标签: transactions sequelize.js


    【解决方案1】:
    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();
    }
    

    【讨论】:

    • 这不起作用。 t 在这种情况下是 Promise 而不是事务对象。
    • @Pier, await 等待 sequelize.transaction() 然后得到它的结果。 t 不是promise,它是promise 的结果。
    • 在执行 .findOne() 命令时,我似乎无法等待工作。它适用于这个吗?
    • 如果transaction = await sequelize.transaction(); 失败了怎么办?然后transaction.rollback() 会抛出一个错误。我们是否需要检查 .rollback 在 catch 块中的事务上是否可用?
    • 在我将事务作为键:值传递之前,它在我的情况下不起作用。例如,在上述解决方案中,{transaction:transaction} 正在工作。我正在使用续集版本 5.19.2
    【解决方案2】:

    以上代码在destroy调用中有错误。

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

    事务是选项对象的一部分。

    【讨论】:

      【解决方案3】:

      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.
      })
      

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

      【讨论】:

      • 无需尝试,抓住?
      【解决方案4】:

      接受的答案是“非托管事务”,它要求您显式调用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);
      }
      

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

      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);
      }
      

      如果任何代码在事务块内抛出错误,则自动触发回滚。

      【讨论】:

      • 非常感谢,我一直在寻找这个解决方案。没想到你可以等待sequelize.transaction
      • @hellowill89 - 您可以查看给定函数的文档。如果它返回一个 Promise,那么你可以使用 await。
      • Property 'transaction' does not exist on type 'typeof import("/Users/mac/Projects/myinvoice-be/node_modules/sequelize/types/index")'. Did you mean 'Transaction'?ts(2551) 我已经从import sequelize from 'sequelize';导入了sequelize
      • 我想这是一个很好的完整性答案,但我不知道为什么我希望间接抛出错误以回滚,而不是明确说明它。也许如果你做得足够多,它会更好,但我自己更喜欢显式版本。
      • @JoelM 因为这是在托管事务中回滚的唯一方法。没有transaction.rollback。
      【解决方案5】:
      async () => {
        let t;
      
        try {
          t = await sequelize.transaction({ autocommit: true});
      
          let _user = await User.create({}, {t});
      
          let _userInfo = await UserInfo.create({}, {t});
      
          t.afterCommit((t) => {
            _user.setUserInfo(_userInfo);
            // other logic
          });
        } catch (err) {
          throw err;
        }
      }
      

      【讨论】:

        【解决方案6】:

        如果启用了 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(...);
        

        用法:

        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`
        }
        

        它是如何工作的?

        来自 Sequelize 源代码:github.com/sequelize

        Check and save transaction to CLS

        if (useCLS && this.sequelize.constructor._cls) {
            this.sequelize.constructor._cls.set('transaction', this);
        }
        

        Retrieve transaction from CLS and set to options

        if (options.transaction === undefined && Sequelize._cls) {
            options.transaction = Sequelize._cls.get('transaction');
        }
        

        了解更多:

        1. Sequelize: automatically pass transactions to all queries
        2. CLS hooked
        3. Async Hooks

        【讨论】:

          【解决方案7】:

          //试试这个

          const transaction = await sequelize.transaction({ autocommit: false });
              try {
                await Model.create(data, {transaction})
              } catch (e) {
                if (transaction) await transaction.rollback();
                next(e);
                response.status(500).json({ error: e });
              }
          
              if (transaction) {
                await transaction.commit();
              }

          【讨论】:

            猜你喜欢
            • 2018-09-13
            • 1970-01-01
            • 2021-03-26
            • 1970-01-01
            • 1970-01-01
            • 2018-06-08
            • 2017-02-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多