2013-04-02 18 views
6

Czy ktoś może podać przykład, w jaki sposób mogę osiągnąć transakcje MySQL w Node.js. Próbuję uzyskać głowę za pomocą sterownika node-mysql i node-mysql-queue.Node.js mysql transakcja

O ile mogę powiedzieć, użycie node-mysql-queue znacznie redukuje asynchroniczną naturę Node.js, ponieważ nowe zapytania muszą poczekać do ukończenia istniejących. Aby obejść ten problem, ktoś próbował połączyć węzeł-mysql-queue z możliwościami łączenia węzłów mysql. to jest uruchamianie nowego połączenia mysql dla każdego nowego żądania HTTP i uruchamianie kolejek transakcji dla poszczególnych połączeń?

Odpowiedz

7

Poniższy przykład transakcja została dodana do dokumentacji miesiąc temu:

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

To naprawdę nie rozwiązać problem asynchronicznej. Połączenie powinno być używane wyłącznie do transakcji, dopóki transakcja nie zostanie zakończona. – bvs

0

mam wymyślić rozwiązanie z użyciem funkcji rekurencyjnej.

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

Korzystam z następującego podejścia. W moim Modelu jest funkcja dodawania, w której wykonuję operacje na bazie danych.

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 
} 

i dzwoni z kontrolerem:

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

Spędziłem trochę czasu na pisanie uogólnioną wersję przykład transakcji danym przez węzeł mysql, więc myślałem, że chciałbym to zrobić tutaj. Używam Bluebird jako mojej obiecującej biblioteki i użyłem jej do "promisify" obiektu połączenia, który bardzo uprościł logikę asynchroniczną.

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

Jeśli chcesz użyć buforowania, jak zasugerowano w pytaniu, można łatwo przełączać linię createConnection z myPool.getConnection(...) i przełączać connection.end linie z connection.release().

0

Znalazłem użyteczne linki, które używają węzła js mysql do łączenia z transakcją. Baza danych Łączenie połączeń jest zawsze przydatne. Można sprawdzić ten link

https://github.com/mysqljs/mysql