Node.js的mysql事务

任何人都可以提供一个如何在Node.js中实现MySQL事务的例子。 我正在尝试使用node-mysql驱动程序和node-mysql-queue。

据我所知,使用node-mysql-queue大大降低了Node.js的asynchronous性质,因为新的查询必须等到现有的查询完成。 为了解决这个问题,有人试图将node-mysql-queue和node-mysql的连接池function结合起来。 即为每个新的http请求启动一个新的mysql连接,并在单个连接上启动事务队列?

以下事务示例是在一个月前的文档中添加的:

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

我正在使用以下方法。 在我的模型中,我正在执行数据库操作。

  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 } 

并从控制器呼叫:

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

我已经想出了一个使用recursion函数的解决scheme。

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

我花了一些时间来写一个由节点mysql给出的事务例子的通用版本,所以我想我会在这里分享它。 我使用蓝鸟作为我的承诺库,并用它来'promisify'连接对象,它简化了asynchronous逻辑了很多。

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

如果您想按照问题中的build议使用池,则可以使用myPool.getConnection(...)轻松切换createConnection行,并使用connection.release()切换connection.end行。

Interesting Posts