web-dev-qa-db-ja.com

Node.js 7 async / awaitでsequelizeトランザクションを使用する方法は?

Node.js 7以降は、既にasync/await構文をサポートしています。続編トランザクションでasync/awaitを使用するにはどうすればよいですか?

47
qiushijie
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();
}
105
user7403683

受け入れられる答えは「アンマネージドトランザクション」であり、commitおよびrollbackを明示的に呼び出す必要があります。 「管理されたトランザクション」が必要な人にとって、これは次のようになります。

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

トランザクションブロック内でエラーをスローするコードがある場合、ロールバックが自動的にトリガーされます。

29
kosinix

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

エラーが発生した場合、トランザクションは自動的にロールバックされます。

5
rlib

上記のコードにはdestroy呼び出しでエラーがあります。

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

トランザクションは、オプションオブジェクトの一部です。

4
Suhail Ansari
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
SuperC

上記のuser7403683ソリューションのテスト範囲については、sequelize-mockおよびsinonの使用を検討してください。

import SequelizeMock from 'sequelize-mock';
import sinon from 'sinon';

sandbox.stub(models, 'sequelize').returns(new SequelizeMock());

成功したトランザクションの場合:


sandbox.stub(model.sequelize, 'transaction')
          .resolves({commit() {}});

and stub everything in the transaction block

commit() {} provides stubbing of transaction.commit(), 
otherwise you'll get a "method does not exist" error in your tests

または失敗したトランザクション:

sandbox.stub(models.sequelize, 'transaction').resolves({rollback() {}});

to cover transaction.rollback()

catch()ロジックをテストします。

0
DeeZone