Node中的MySQL事务工具类,可以直接使用

在最近项目中,由于业务需求,导致需要同时操作12张表。由于之前在node开发中没有使用过事务,所以就去了解了一下。其实node中事务和java是一样的,只不过java中我们可以通过注解的方式来实现事务的回滚,但是在node中,想要实现事务就需要将SQL一条一条的执行,执行完成之后再commit。于是乎就有了这个工具类,逻辑有点傻,但是很实用。
1、创建一个Tool文件夹,再创建一个MySQL_dbHelper.js事务工具类,代码如下:

/**
 * 数据库事务工具
 */

var mysql = require('promise-mysql');
var config = require('../../../config');
var SqlString = require('sqlstring');
var async = require("async");
module.exports = {
    /**
     * 组装SQL_map
     * @param sql sql语句
     * @param params 数组,如果存在占位符,传入[xx,xx,xx],如果没有传入[]
     * @param callback
     * @returns {*}
     * @private
     */
    _getNewSqlParamEntity:function(sql, params, callback) {
        if (callback) {
            return callback(null, {
                sql: sql,
                params: params
            });
        }
        return {
            sql: sql,
            params: params
        };
    },
    /**
     * 事务管理
     * @param sqlparamsEntities SQL_map {sql: param:}
     * @param callback 回调
     */
    execTrans:function  (sqlparamsEntities, callback) {
        var name='';
        if(!name) {
            name = 'default';
        }
        var db_config = config['mysql'][name];
        db_config.queryFormat = function (query, values) {
            //console.log(query, values);
            if (query.indexOf('?') != -1) {
                return SqlString.format(query, values, db_config.stringifyObjects, db_config.timezone);
            }
            else {
                return query.replace(/\:(\w+)/g, function (txt, key) {
                    if (values && values.hasOwnProperty(key)) {
                        return this.escape(values[key]);
                    }
                    return txt;
                }.bind(this));
            }
        };
        var pool  = mysql.createPool(db_config);
        pool.getConnection(function (err, connection) {
            if (err) {
                return callback(err, null);
            }
            connection.beginTransaction(function (err) {
                if (err) {
                    return callback(err, null);
                }
                //console.log("开始执行transaction,共执行" + sqlparamsEntities.length + "条数据");
                var funcAry = [];
                sqlparamsEntities.forEach(function (sql_param) {
                    var temp = function (cb) {
                        var sql = sql_param.sql;
                        var param = sql_param.params;
                        connection.query(sql, param, function (tErr, rows, fields) {
                            if (tErr) {
                                connection.rollback(function () {
                                    return  callback(tErr,"事务失败," + sql_param + ",ERROR:" + tErr);
                                });
                            } else {
                                return cb (null, 'ok');
                            }
                        })
                    };
                    funcAry.push(temp);
                });

                async.series(funcAry, function (err, result) {
                    if (err) {
                        connection.rollback(function (err) {
                            console.log("transaction error: " + err);
                            connection.release();
                            return callback(err, null);
                        });
                    } else {
                        connection.commit(function (err, info) {
                            //console.log("transaction info: " + JSON.stringify(info));
                            if (err) {
                                console.log("执行事务失败," + err);
                                connection.rollback(function (err) {
                                    console.log("transaction error: " + err);
                                    connection.release();
                                    return callback(err, null);
                                });
                            } else {
                                connection.release();
                                return callback(null, info);
                            }
                        })
                    }
                })
            });
        });
    }
};

如果没有promise-mysql,sqlstring,async的,就手动npm install一下。
其中config是我的配置文件,你也可以将MySQL的配置写在MySQL_dbHelper.js里面。
config.js代码如下:


var config = {
	 mysql: {
        // 默认配置
        default: {
            host: 'localhost',
            port: 3306,
            user: 'root',
            password: '***',
            database: '数据库名',
            acquireTimeout: 2000,
            connectionLimit: 100
    },
	}

2、数据交互层调用事务工具

var dbHelpers = require('../../Tool/MySQL_dbHelper');
exports.To_dbHelper=function (param,cb) {
    var sqlParamsEntity = [];//装载所有待执行的SQL和数据
    /****解析map里面不同的SQL并匹配对应的占位数据***/
    for(var column in param){
        /***第一层取出,map{map{}}***/
        var keyName =[];
        for(var columns in param[column]){//第二层map为{xx:[],xx:[]}
            keyName.push(columns);
        }
        for(var i in param[column][keyName[0]]){
            console.log('sql====='+param[column][keyName[0]][i]);
            console.log('whereParam====='+param[column][keyName[1]][i]);
            sqlParamsEntity.push(dbHelpers._getNewSqlParamEntity(param[column][keyName[0]][i],param[column][keyName[1]][i]));
        }
    }
    dbHelpers.execTrans(sqlParamsEntity, function (err, info) {
        if (err) {
            console.error("事务执行失败" + err);
            cb(err, '失败')
        } else {
            cb(null, '成功')
        }
    });
};

3、控制层封装SQL及其占位数据。

router.post('/To_examine.do',async function (req,res) {
	try{
		var sql1 = [];//执行的SQL
        var sql2 = [];
        var sql3 = [];
        var sql1_param = []; //SQL中找占位符对应的数据集[ [占位数据,占位数据], [占位数据,占位数据] ]
        var sql2_param = [];
        var sql3_param = []
        //这里就简单的封装一下3个SQL,并不是真实的
        for(var i=0;i<=5:i++){
			sql1.push('insert into user_info (id,name,age,sex) value(?,?,?,?)');
			sql1_param.push([3+i+1,‘张三’+i],22,'男']);
			sql2.push('update user_info name=? where id =?');
			sql2_param.push(['女',i+12]);
			sql3.push('delect user_Score  where id =?');
			sql3_param.push([i+1]);
	}
	var param = {sql1:{sql1:sql1,sql1_param},sql2:{sql2:sql2,sql2_param},sql3:{sql3:sql3,sql3_param}};//封装成这样是为了module成循环解析
	 moudle.To_dbHelper(params,function (err,data) {
            if(err){
                console.log(err);
                app_utils.respMsg(res, false, 4000, err, null, null);
            }else{
                app_utils.respMsg(res, true, 4000, '成功', null, null);//这里记得一定要返回结果给页面,不然会重复执行一次
            }
        });
	}catch(err){
		 console.log(err);
	}
	});

好了,整个事务工具类的创建和使用就已经完成了。按照步骤做就可以了,在控制层调用module层方法的时候,一定要对视图层返回结果,不然事务会执行两次,我之前写好的时候为了看效果就没有返回视图层,导致执行了两次事务,找了半天都没有找到原因,结果加了返回就可以了。
如有什么错误的地方,欢迎留言。如果你有更好的方法,那请留言告诉我。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值