Node.js 7以降は、既にasync/await構文をサポートしています。続編トランザクションでasync/awaitを使用するにはどうすればよいですか?
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();
}
受け入れられる答えは「アンマネージドトランザクション」であり、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);
}
トランザクションブロック内でエラーをスローするコードがある場合、ロールバックが自動的にトリガーされます。
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.
})
エラーが発生した場合、トランザクションは自動的にロールバックされます。
上記のコードにはdestroy呼び出しでエラーがあります。
await Model.destroy({where: {id}, transaction});
トランザクションは、オプションオブジェクトの一部です。
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;
}
}
上記の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()
ロジックをテストします。