2013-04-02 9 views
6

Kann jemand ein Beispiel dafür geben, wie ich MySQL-Transaktionen in Node.js erreichen konnte. Ich versuche, mit dem Knoten-mysql-Treiber und Knoten-mysql-queue herumzukommen.Node.js mysql transaction

Soweit ich feststellen kann, reduziert die Verwendung von node-mysql-queue die asynchrone Natur von Node.js erheblich, da neue Abfragen warten müssen, bis die bestehenden abgeschlossen sind. Um dies zu umgehen, hat jemand versucht, Knoten-Mysql-Queue mit Knoten-Mysql Verbindung-Pooling-Fähigkeiten zu kombinieren. d. h. eine neue mysql-verbindung für jede neue http-anfrage starten und transaktionsschlangen bei einzelnen verbindungen starten?

Antwort

7

Die folgende Transaktion Beispiel wurde vor einem Monat in der Dokumentation hinzugefügt:

https://github.com/felixge/node-mysql#transactions

connection.beginTransaction(function(err) { 
    if (err) { throw err; } 
    connection.query('INSERT INTO posts SET title=?', title, function(err, result) { 
    if (err) { 
     connection.rollback(function() { 
     throw err; 
     }); 
    } 

    var log = 'Post ' + result.insertId + ' added'; 

    connection.query('INSERT INTO log SET data=?', log, function(err, result) { 
     if (err) { 
     connection.rollback(function() { 
      throw err; 
     }); 
     } 
     connection.commit(function(err) { 
     if (err) { 
      connection.rollback(function() { 
      throw err; 
      }); 
     } 
     console.log('success!'); 
     }); 
    }); 
    }); 
}); 
+3

Dies ist nicht wirklich von dem Asynchron-Problem beheben. Die Verbindung sollte ausschließlich für die Transaktion verwendet werden, bis die Transaktion abgeschlossen ist. – bvs

0

ich mit einer Lösung zu kommen haben eine rekursive Funktion.

var sql = 'INSERT INTO logs SET data = ?'; 

// array of rows to insert 
var rows = [[/*first row*/], [/*additional row*/]]; 

connection.beginTransaction(function (err) { 

    if (err) { 
     throw err; 
    } 

    var insertEachRow = function() { 

     var row = rows.shift(); 

     if (! row) { 
      // Done, now commit 
      return noMoreRows(); 
     } 

     connection.query(sql, row, function (err, result) { 
      if (err) { 
       connection.rollback(function() { 
        throw err; 
       }); 
      } 

      insertEachRow(); 
     }); 
    }; 

    var noMoreRows = function() { 
     connection.commit(function (err) { 
      if (err) { 
       connection.rollback(function() { 
        throw err; 
       }); 
      } 
      console.log('success!'); 
     }); 
    }; 

    insertEachRow(); 
}); 
1

Ich verwende den folgenden Ansatz. Es gibt eine Add-Funktion in meinem Modell, wo ich Datenbankoperationen durchführe.

add : function (data, callback) { 

    //Begin transaction 
    connection.beginTransaction(function(err) { 
     if (err) { 
      throw err; 
     } 

     var user_query = "INSERT INTO `calldata`.`users` (`username`, `password`, `enabled`, `accountNonExpired`, `accountNonLocked`, `credentialsNonExpired`) VALUES ('" + data.mobile + "', '" + sha1(data.password) + "', '1', '1', '1', '1')"; 
     connection.query(user_query, function(err, results) { 
      if (err) { 
       return connection.rollback(function() { 
        throw err; 
       }); 
      } 

      var accnt_dtls_query = "INSERT INTO `calldata`.`accnt_dtls` (`req_mob_nmbr`, `usr_nme`, `dvce_id`, `mngr_id`, `cmpny_id`, `actve_flg`, `crtd_on`, `usr`) VALUES (" + data.mobile + ", '" + data.name + "', '', " + data.managerId + ", " + data.companyId + ", 1, now(), '" + data.mobile+ "')"; 

      connection.query(accnt_dtls_query, function(err, results) { 
       if (err) { 
        return connection.rollback(function() { 
         throw err; 
        }); 
       } 
       var user_role_query = "INSERT INTO `calldata`.`user_roles` (`username`, `ROLE`) VALUES ('" + data.mobile + "', '" + data.role + "')"; 

       connection.query(user_role_query, function(err, result) { 
        if (err) { 
         return connection.rollback(function() { 
          throw err; 
         }); 
        } 

        //add an entry to manager table 
        var mngr_dtls_query = "INSERT INTO `calldata`.`mngr_dtls` (`mngr_nm`, `cmpny_id`, `crtd_on`, `usr_nm`, `eml_id`) VALUES ('" + data.name + "'," + data.companyId + " , now(), '" + data.mobile + "', '" + data.mobile + "')"; 
        connection.query(mngr_dtls_query, function(err, result) { 
         if (err) { 
          return connection.rollback(function() { 
           throw err; 
          }); 
         } 
         console.log('Changed ' + result.changedRows + ' results'); 
         connection.commit(function (err) { 
          console.log('Commiting transaction.....'); 
          if (err) { 
           return connection.rollback(function() { 
            throw err; 
           }); 
          } 

          console.log('Transaction Complete.'); 
          connection.end(); 
          callback(null, result); 
         }); 
        }); 
       }); 
      }); 
     }); 
    }); 
    //transaction ends here 
} 

und fordern von der Steuerung:

agentAccountModel.add(data, function(err, results) { 
       if(err) 
       { 
        res.status(500); 
        res.json({ 
         "status": 500, 
         "message": err 
        }); 
       } 

       res.status(200); 
       res.json({ 
        "status": 200, 
        "message": "Saved successfully" 

       }); 
      }); 
1

ich einige Zeit damit verbracht eine verallgemeinerte Version des Transaktions Beispiel durch Knoten mysql gegeben zu schreiben, so dass ich dachte, dass ich sie hier teilen würde. Ich verwende Bluebird als meine Versprechens-Bibliothek, und benutzte sie, um das Verbindungsobjekt zu promisifizieren, was die asynchrone Logik sehr vereinfacht hat.

const Promise = ('bluebird'); 
const mysql = ('mysql'); 

/** 
* Run multiple queries on the database using a transaction. A list of SQL queries 
* should be provided, along with a list of values to inject into the queries. 
* @param {array} queries  An array of mysql queries. These can contain `?`s 
*        which will be replaced with values in `queryValues`. 
* @param {array} queryValues An array of arrays that is the same length as `queries`. 
*        Each array in `queryValues` should contain values to 
*        replace the `?`s in the corresponding query in `queries`. 
*        If a query has no `?`s, an empty array should be provided. 
* @return {Promise}   A Promise that is fulfilled with an array of the 
*        results of the passed in queries. The results in the 
*        returned array are at respective positions to the 
*        provided queries. 
*/ 
function transaction(queries, queryValues) { 
    const connection = mysql.createConnection(databaseConfigs); 
    Promise.promisifyAll(connection); 
    return connection.connectAsync() 
    .then(connection.beginTransactionAsync()) 
    .then(() => { 
     const queryPromises = []; 

     queries.forEach((query, index) => { 
      queryPromises.push(connection.queryAsync(query, queryValues[index])); 
     }); 
     return Promise.all(queryPromises); 
    }) 
    .then(results => { 
     return connection.commitAsync() 
     .then(connection.endAsync()) 
     .then(() => { 
      return results; 
     }); 
    }) 
    .catch(err => { 
     return connection.rollbackAsync() 
     .then(connection.endAsync()) 
     .then(() => { 
      return Promise.reject(err); 
     }); 
    }); 
} 

Wenn Sie Pooling verwenden wollte, wie Sie in der Frage vorgeschlagen, könnte man leicht wechseln die createConnection Linie mit myPool.getConnection(...), und schalten Sie die connection.end Linien mit connection.release().

0

Ich fand eine nützliche Links, die Knoten js mysql Pooling mit Transaktion verwendet. Das Datenbankverbindungs-Pooling ist immer nützlich. Man kann diesen Link überprüfen

https://github.com/mysqljs/mysql