Maison  >  Questions et réponses  >  le corps du texte

Meilleur moyen de gérer efficacement les transactions à l'aide de Promises

Je crée une classe utilitaire pour NodeJs pour m'aider à gérer les transactions de base de données.

Mon idée est de créer une méthode comme celle-ci :

transactionBlock(params) {
    let _db;
    return mySqlConnector.getConnection(params.db)
        .then(db => {
            _db = db;
            console.log(`beginTransaction`);
            return db.beginTransaction()
        })
        .then(() => {
            return Promise.resolve(_db);
        })
        .catch((e) => {
            console.log(`roolback`);
            _db.rollback();
        })
        .finally(() => {
            console.log(`commit`);
            _db.commit();
        })
}

et utilisez-le comme ceci :

const params = {db:"my_db"};
transactionBlock(params)
    .then(db =>{
        console.log(`do query 1`);
        db.insert(....)
        console.log(`do query 2`);
        db.insert(....)
        console.log(`do query 3`);
        db.insert(....)
    })

J'espérais que ça marcherait, mais apparemment le résultat est le suivant :

beginTransaction
commit
do query 1
do query 2
do query 3

Pensez-vous qu'il est possible de créer une fonction transactionBlock 返回一个承诺,用户可以在其中执行查询,最后,如果所有查询都正常,函数 transactionBlock qui effectuera le commit ?

J'utilise ceci : npmjs.com/package/promise-mysql

Merci Au revoir

P粉226667290P粉226667290191 Il y a quelques jours399

répondre à tous(1)je répondrai

  • P粉512363233

    P粉5123632332024-03-31 10:11:13

    Le gros problème avec votre approche actuelle est que finally() toujours s'exécute indépendamment du fait que la chaîne de promesses soit résolue ou rejetée, vous ne voulez donc certainement pas y engager de transaction.

    Je ne vois qu'une seule option ici... nécessite une fonction de rappel représentant le corps de la transaction.

    En général, je recommande également d'utiliser la syntaxe async / wait pour une meilleure lisibilité.

    const transactionBlock = async (connectionName, txBody) => {
      const db = await mySqlConnector.getConnection(connectionName);
      await db.beingTransaction();
      try {
        await txBody(db);
        console.log("commit");
        return db.commit(); // all good, commit
      } catch (err) {
        console.error("rollback", err);
        await db.rollback();
        // keep the rejection chain going by re-throwing the error or a new one
        throw err; // or perhaps `new Error("DB error: " + err.message)`
      }
    };
    

    Appelle comme ça

    try {
      await transactionBlock("my_db", async (db) => {
        console.log(`do query 1`);
        await db.insert(/* ... */);
        console.log(`do query 2`);
        await db.insert(/* ... */);
        console.log(`do query 3`);
        await db.insert(/* ... */);
      });
    } catch (err) {
      console.error("oh no, something went wrong", err);
    }
    

    Si vous utilisez Typescript, les interfaces et types suivants garantiront un fonctionnement fluide

    type TxBody = (db: Connection) => Promise;
    type TransactionBlock = (
      connectionName: string,
      txBody: TxBody
    ) => Promise;
    
    const transactionBlock: TransactionBlock = async (connectionName, txBody) => {
      // ...
    };
    

    répondre
    0
  • Annulerrépondre