Node.js 7 how to use sequelize transaction with async / await?

前端 未结 6 1189
没有蜡笔的小新
没有蜡笔的小新 2021-01-29 21:43

Node.js 7 and up already support async/await syntax. How should I use async/await with sequelize transactions?

相关标签:
6条回答
  • 2021-01-29 21:55

    The answer given by user7403683 describes async/await way for unmanaged transaction (http://docs.sequelizejs.com/manual/tutorial/transactions.html#unmanaged-transaction-then-callback-)

    Managed transaction in async/await style may look as follows:

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

    If error occurs, the transaction is automatically rolled back.

    0 讨论(0)
  • 2021-01-29 22:01

    The accepted answer is an "unmanaged transaction", which requires you to call commit and rollback explicitly. For anyone who wants a "managed transaction", this is what it would look like:

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

    To rollback, just throw an error inside the transaction function:

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

    If any code that throws an error inside the transaction block, the rollback is automatically triggered.

    0 讨论(0)
  • 2021-01-29 22:05

    The above code has an error in destroy call.

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

    Transaction is part of the options object.

    0 讨论(0)
  • 2021-01-29 22:06
    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;
      }
    }
    
    0 讨论(0)
  • 2021-01-29 22:09

    If CLS is enabled, Sequelize can use that to keep your transaction object and automatically pass it to all queries inside the continuation-passing cycle.

    Setup:

    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(...);
    

    Usage:

    const removeUser = async (id) => {
        await sequelize.transaction(async () => { // no need `async (tx)`
            await removeClasses(id);
            await User.destroy({ where: { id } }); // will auto receive `tx`
        });
    }
    
    const removeClasses = 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`
    }
    

    How it works?

    From Sequelize source code: 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 CSL and set to options

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

    Read more:

    1. Sequelize: automatically pass transactions to all queries
    2. CLS hooked
    3. Async Hooks
    0 讨论(0)
  • 2021-01-29 22:17
    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();
    }
    
    0 讨论(0)
提交回复
热议问题