71 votes

Node.js 7 comment utiliser la transaction sequelize avec async / await ?

Node.js 7 et plus supporte déjà la syntaxe async/await. Comment dois-je utiliser async/await avec les transactions sequelize ?

164voto

user7403683 Points 852
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 votes

Ça ne marche pas. t dans ce cas, est une Promise et non l'objet de la transaction.

10 votes

@Pier, await attend la sequelize.transaction() et en obtient ensuite le résultat. le t n'est pas la promesse, c'est le résultat de la promesse.

0 votes

Je n'arrive pas à faire fonctionner l'attente lorsque je fais une commande .findOne(). Cela fonctionne-t-il avec ceci ?

62voto

kosinix Points 391

La réponse acceptée est une "transaction non gérée", qui vous oblige à appeler commit y rollback explicitement. Pour quiconque souhaite une "transaction gérée", voici à quoi elle ressemblerait :

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

Pour faire marche arrière, il suffit de lancer une erreur dans la fonction de transaction :

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

Si un code qui lance une erreur à l'intérieur du bloc de transaction, le rollback est automatiquement déclenché.

0 votes

Merci beaucoup, cela fait un moment que je cherche cette solution. Je n'avais pas réalisé qu'on pouvait attendre sequelize.transaction .

0 votes

@hellowill89 - vous pouvez vérifier la documentation d'une fonction donnée. Si elle renvoie une Promise, alors vous pouvez utiliser await.

0 votes

Property 'transaction' does not exist on type 'typeof import("/Users/mac/Projects/myinvoice-be/node_modules/sequel‌​ize/types/index")'. Did you mean 'Transaction'?ts(2551) J'ai importé sequelize de import sequelize from 'sequelize';

7voto

rlib Points 788

La réponse donnée par l'utilisateur7403683 décrit la méthode async/await pour les transactions non gérées ( http://docs.sequelizejs.com/manual/tutorial/transactions.html#unmanaged-transaction-then-callback- )

Une transaction gérée dans le style async/await peut se présenter comme suit :

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

En cas d'erreur, la transaction est automatiquement annulée.

0 votes

Pas besoin de try, catch ?

3voto

Suhail Ansari Points 41

Le code ci-dessus a une erreur dans l'appel destroy.

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

La transaction fait partie de l'objet des options.

0voto

DeeZone Points 225

Pour la couverture de test de la solution de l'utilisateur7403683 ci-dessus, envisagez d'utiliser sequelize-mock y sinon :

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

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

pour des transactions réussies :

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

ou une transaction échouée :

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

to cover transaction.rollback()

pour tester le catch() logique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X