- Nodejs+mysql简单封装增删改查方法
 
Nodejs+mysql简单封装增删改查方法
在express中进行mysql的连接
express -e test_mysql -y
生成项目
cd test_mysql
进入项目
npm start 是可以启动服务的
下面我们来一步步连接mysql数据库
环境准备 mysql和navicat for mysql
如果你的电脑没有安装mysql和navicat,安装mysql和navicat for mysql的安装教程就不说,请自行查阅资料并安装好
首先,我们使用navicat连接上本地mysql服务器,并创建node_test数据库,然后运行下面代码:
CREATE TABLE IF NOT EXISTS `node_book` (
  `book_id` int(11) NOT NULL AUTO_INCREMENT,
  `book_name` varchar(100) COLLATE utf8_bin NOT NULL,
  `author` varchar(100) COLLATE utf8_bin NOT NULL,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`book_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=4 ;
此代码会在node_test下生成一个表
开始吧
在项目下创建config文件夹
创建好之后,再再config文件夹下创建dbconfig.json文件,内容是:
{
  "db" : {
    "host" : "localhost",
    "port" : "3306",
    "user" : "root",
    "password" : "123456",
    "dbName" : "node_test"
  }
}
解释:很显然,这是一个json文件,并且,里面只有一个db属性,db中包含的就是数据库的信息,host是主机,port是端口号,user是用户名,password是数据库登陆密码,dbName是数据库名。
很多人的mysql安装的时候是没有设置密码的,由于编者这本地的数据库是密码是123456,所有这里多了个数据库的密码。
至于dbName,就是你使用navicat创建的数据名。
在项目文件夹下创建util文件夹
创建好后,并在util文件夹下创建util.js并输入一下内容
var fs  = require('fs')//引入文件模块
, sys = require('util');//引入常用工具模块
/**
 * 获取json文件中的key的
 * @param fileName 文件路径+文件名
 * @param key 属性名key
 * @returns {*}
 */
exports.get = function(fileName, key){
    var configJson = {};
    try{
        var str = fs.readFileSync(fileName,'utf8');//读取json文件
        configJson = JSON.parse(str);//将字符转成对象类型
    }catch(e){
        sys.debug("JSON 解析错误")
    }
    return configJson[key];//返回key的对象
}
解释:
fs.readFileSync(fileName,’utf8’):以UTF格式同步读取配置文件信息
consfigJson = JSON.parse(str):使用JSON的parse方法解析读取后的配置文件内容转化为json对象
return configJson[key]:返回需要的key值配置信息
这是一个通用工具文件,util的get方法是获取json文件下的某个key信息
既然都工具都写好了,那怎么用呢,下面就是重点了
导入mysql的包
npm install mysql 项目中用到的mysql模块,有了这些才能开始连接数据库
在项目文件夹创建model文件夹
创建好之后,接着在model下面创建base_model.js
var Util = require('../util/util.js')
, mysql = require('mysql')
, dbClient;
module.exports = function(){
    __constructor();
 	/**
     *
     * 数据库连接构造函数
     */
    function __constructor(){
        var dbConfig = Util.get('./config/dbconfig.json', 'db');
        /* 获取mysql配置信息 */
        client = {};
        client.host = dbConfig['host'];
        client.port = dbConfig['port'];
        client.user = dbConfig['user'];
        client.password = dbConfig['password'];
        dbClient = mysql.createConnection(client);
        dbClient.connect();
        /* 执行mysql指令,连接mysql服务器的一个数据库 */
        dbClient.query('USE ' + dbConfig['dbName'], function(error, results) {
            if(error) {
                console.log('数据库连接错误: ' + error.message);
                dbClient.end();
            }
            console.log('数据库'+dbConfig['dbName']+' 连接成功!');
        });
    }
}
解释:
- mysql = require(‘mysql’):获取MySQL模块对象
 - __constructor();//调用自身的构造器,其方法在本函数中定义
 - function __constructor(){}:定义私有构造函数 __constructor
 
我们先从BaseModel的构造函数开始走流程,__constructor涉及数据库的连接,因此需要一些配置信息,这里通过一个util.js工具类来存放一些公用方法,包含json配置文件解析的方法。
- dbConfig = Util.get(‘config.json’,’db’):读取config.json配置文件,并获取db的配置信息
 - client.host = dbConfig[‘host’]:数据库连接服务器的host。
 - client.port = dbConfig[‘port’]:数据库连接服务器的端口。
 - client.user = dbConfig[‘user’];数据库连接的用户名
 - client.password = dbConfig[‘password’];数据库连接的用户密码
 - dbClient = mysql.createConnection(client);创建MySQL服务器的连接对象
 - dbClient = connect():连接MySQL服务器
 - dbClient.query(‘USE ‘ + dbConfig[‘dbName’], function(error, results) {…}执行数据的MySQL操作,use关键字是来简介M有SQL中的一个MySQL数据库
 
下面,我们的mysql连接已经写好了,那么如何来测试数据库连接是否能成功连接与否呢。
测试mysql数据库连接
我们在 routes文件夹下添加一个test.js
var express = require('express');
var router = express.Router();
var BaseModel = require('../model/base_model.js');
/* GET test page. */
router.get('/', function(req, res, next) {
    var baseModel = new BaseModel();//创建baseModel实例
    res.render('index', { title: 'test mysql' });
});
module.exports = router;
解释:
var BaseModel = require(‘../model/base_model.js’);//引用base_model模块,用于连接数据库
var baseModel = new BaseModel();//创建baseModel实例 数据库已经正确连接
在app.js中引入test.js的路由
...
var index = require('./routes/index');
var users = require('./routes/users');
var test = require('./routes/test');
var app = express();
...
...
...
app.use('/', index);
app.use('/users', users);
app.use('/test', test);
...
这时候,重启服务器
npm start
并在你的浏览器中访问 http://localhost:3000/test
看后台,你会发现

此时,你的数据都已经连接成功了。
那么,我们开始对数据库的增删改查进行简单的封装。
(增)在某张表中insert一条数据
让我们回到base_model.js中来,在base_model.js中第13行左右,添加insert方法
...
module.exports = function(){
	__constructor();
/**
 *
 * @desc 向数据库插入数据
 * @param tableName string
 * @param rowInfo json
 * @param callback function
 * @return null
 */
this.insert = function(tableName, rowInfo, callback){
    dbClient.query('INSERT INTO ' + tableName + ' SET ?', rowInfo, function(err, result) {
        if (err) throw err;
        callback(result.insertId);
    });
};
...
- dbClient.query(‘INSERT INTO ‘ + tableName + ‘ SET ?’, rowInfo,…,会将rowInfo的json数据转化为key = value的形式。
 - callback(result.insertId):result.insertId为插入数据后返回的主键值,并将执行结果交由回调函数处理
 
测试增加 insert方法
在test.js中,添加如下代码
..
router.get('/', function(req, res, next) {
var baseModel = new BaseModel();
var tableName = 'node_book';
/*数据插入验证 */
var rowInfo = {};
var tableName = 'node_book';
rowInfo.book_name = 'minchao book';
rowInfo.author = 'minchao';
console.log(tableName+"....."+ JSON.stringify(rowInfo));
baseModel.insert(tableName, rowInfo, function(ret){
    console.log(JSON.stringify(ret));
});
res.render('index', { title: 'test mysql' });
.. 解释:
- rowInfo = {}:初始化一个json对象
 - rowInfo.book_name:设置json需要插入数据库的boo_name变量
 - rowInfo.author = ‘minchao’;设置json需要插入数据库的author变量
 - baseModel.insert(tableName, rowInfo,…;调用baseModel中的insert基类方法,向数据库插入数据
 - console.log(JSON.stringify(ret));打印回调函数的结果
 
这时候,重启服务器
npm start
并在你的浏览器中访问 http://localhost:3000/test
你会发现后台打印出你插入的行号,也就是插入数据后返回的主键值
此时刷新navicat for mysql的界面,可以看见多了一条数据。
(删)删除数据库某张表中的一条数据
回到base_model.js中来,在base_model.js中insert方法后,添加remove方法
...
/**
 *
 * @desc 删除数据库的一条数据
 * @param tableName string
 * @param idJson json
 * @param rowInfo json
 * @param callback function
 * @return null
 */
this.remove = function(tableName, idJson, callback){
    dbClient.query('delete from ' + tableName + ' where ?', idJson,
        function(error, results) {
            if(error) {
                console.log("ClientReady Error: " + error.message);
                dbClient.end();
                callback(false);
            } else {
                callback(true);
            }
        });
};
...
解释:和insert方法类似
测试删除操作
在routes/test.js中的get方法中添加如下测试代码,注释掉insert的测试代码
	..
 		var tableName = 'node_book';
    var idJson = {'book_id': 3};
    baseModel.remove(tableName, idJson, function(ret){
        console.log(JSON.stringify(ret));//true
    });
	...
重启服务器,发起请求:
npm start
并在你的浏览器中访问 http://localhost:3000/test
你会在后台中是true
并且,刷新navicat for mysql的界面,可以看见id为3的成功删除了
(改)修改数据库的一条数据
回到base_model.js中来,在base_model.js中remove方法后,添加modify方法
/**
 *
 * @desc 修改数据库的一条数据
 * @param tableName string
 * @param idJson json
 * @param callback function
 * @return null
 */
this.modify = function(tableName, idJson, rowInfo, callback){
    dbClient.query('update ' + tableName + ' SET ? where ?', [rowInfo, idJson], function(err, result) {
        if(err) {
            console.log("ClientReady Error: " + err.message);
            callback(false);
        } else {
            callback(result);
        }
    });
};
测试 修改
在test.js中添加
/* modify验证 */
var newInfo = {};
newInfo.book_name = 'nodejs book-by danhuang';
newInfo.author = 'Jimi';
var idJson = {'book_id': 2};
baseModel.modify(tableName, idJson, newInfo, function(ret){
     console.log(JSON.stringify(ret));
});
重启服务器,发起请求:
npm start
并在你的浏览器中访问 http://localhost:3000/test
你会在后台中看见你修改的值
(查)查找一条数据(根据主键查找)
在base_model.js中添加
/**
 *
 * 根据主键id值查询数据库的一条记录
 * @param tableName string
 * @param idJson id
 * @param callback function
 * @return null
 */
this.findOneById = function(tableName, idJson, callback){
    dbClient.query('SELECT * FROM ' + tableName + ' where ?', idJson,
        function(error, results) {
            if (error) {
                console.log('GetData Error: ' + error.message);
                dbClient.end();
                callback(false);
            } else {
                if(results){ //如果查询到数据则返回一条数据即可
                    callback(results.pop());
                } else{ //查询数据为空则返回空数据
                    callback(results);
                }
            }
        });
};
验证根据Id查找(根据主键查找)
在test.js中添加
/* findOneById验证 */
var idJson = {'book_id': 1};
baseModel.findOneById(tableName, idJson, function(ret){
    bookInfo = ret;
    console.log(bookInfo);
});
重启服务器,发起请求:
npm start
并在你的浏览器中访问 http://localhost:3000/test
你会在后台看见你所查找的那一条数据
(查) 条件查询数据
在base_model.js中添加
 /**
 *
 * @desc 条件查询数据
 * @param tableName string
 * @param whereJson json desc(and和or区别,其中的条件为key值、连接符大于小于还是等于、value值)
 * @param orderByJson json desc({'key' : 'time', 'type':'desc'})
 * @param limitArr array desc(第一个元素是返回偏移量,第二个是返回数量,空返回全部)
 * @param fieldsArr array desc(返回哪些字段)
 * @param callback function
 * @return null
 */
this.find = function(tableName, whereJson, orderByJson, limitArr, fieldsArr, callback){
    var andWhere   = whereJson['and']
        , orWhere    = whereJson['or']
        , andArr = []
        , orArr  = [];
    /* 将数组转换为where and条件array */
    for(var i=0; i<andWhere.length; i++){
        andArr.push(andWhere[i]['key'] + andWhere[i]['opts'] + andWhere[i]['value']);
    }
    /* 将数组转换为where or条件array */
    for(var i=0; i<orWhere.length; i++){
        orArr.push(orWhere[i]['key'] + orWhere[i]['opts'] +orWhere[i]['value']);
    }
    /* 判断条件是否存在,如果存在则转换相应的添加语句 */
    var filedsStr = fieldsArr.length>0 ? fieldsArr.join(',') : '*'
        , andStr    = andArr.length>0    ? andArr.join(' and ') : ''
        , orStr     = orArr.length>0     ? ' or '+orArr.join(' or ') : ''
        , limitStr  = limitArr.length>0  ? ' limit ' + limitArr.join(',') : ''
        , orderStr  = orderByJson ? ' order by ' + orderByJson['key'] + ' ' + orderByJson['type'] : '';
    /* 执行mysql语句 */
    dbClient.query('SELECT ' + filedsStr + ' FROM ' + tableName + ' where ' + andStr + orStr + orderStr + limitStr,
        function(error, results) {
            if (error) {
                console.log('GetData Error: ' + error.message);
                dbClient.end();
                callback(false);
            } else {
                callback(results);
            }
        });
};
测试条件查询
在test.js中添加
//book_name 等于nodejs且author等于 danhuang 或者十以内的数据 var whereJson = {    'and' : [{'key':'book_name', 'opts':'=', 'value' : '"nodejs"'}, {'key':'author', 'opts':'=', 'value' : '"danhuang"'}],
    'or' : [{'key':'book_id', 'opts':'<', 'value' : 10}]
};
var fieldsArr = ['book_id','book_name', 'author', 'time'];//查询结果中显示的字段
var orderByJson = {'key':'time', 'type':'desc'};//按照时间降序排序
var limitArr = [0, 3]; //查询结果的前三个
baseModel.find(tableName, whereJson, orderByJson, limitArr, fieldsArr, function(ret){
    console.log(JSON.stringify(ret));
});
- 
    
var whereJson = { ‘and’ : [{‘key’:’book_name’, ‘opts’:’=’, ‘value’ : ‘“nodejs”’}, {‘key’:’author’, ‘opts’:’=’, ‘value’ : ‘“danhuang”’}], ‘or’ : [{‘key’:’book_id’, ‘opts’:’<’, ‘value’ : 10}] };中key为条件键名,opts为条件,value为对比值
 - andWhere = whereJson[‘and’]:获取条件and数组。
 - orWhere = whereJson[‘or’]:获取条件or数组
 - fieldsArr = [‘book_name’, ‘author’, ‘time’]: 返回哪些字段
 - orderByJson = {‘key’:’time’, ‘type’:’desc’}:按time降序排序
 - limitArr = [0, 10];第一个元素是返回偏移量,第二个是返回数量,空返回全部
 
至此,我们就实现了Node.js中MySQL的操作基类,这个基类可以作为所有Model层操作类,使用方法参考test.js,其中包含了所有函数接口的使用方法。需要特别留意的是,本基类没有进行MySQL执行语句的转义处理,在真正的项目应用时,需要引用Node.js的MySQL模块提供的mysql.escape和mysql。escapepeId,避免MySql注入。
        
	  
