Node.JS连接mysql数据库及Cannot enqueue Handshake after invoking quit错误
文章 3848 0 0 0
发布时间:2019年02月26日

概述

当我们使用node.js写网站的时候,难免会有一些操作让我们连接数据库,并对数据库经行操作,但是每次都需要对数据库进行连接与断开连接,所以写一篇关于node + mysql的文章。首先介绍一下node.js连接MySQL的步骤,第一步,需要安装一个叫做MySQL的npm包,这个包是官方提供的,稳定性是可以保证的,当然,也还有其他的npm包,这里我们只使用mysql包。

1、使用npm安装MySQL模块

$ npm install mysql —save

2、在你需要对数据库进行操作的地方引入模块mysql

var mysql = require('mysql');

3、建立连接,并且定义query语句(可以对数据库进行操作)

这里就你要多说几句了,我们通过mysql下的createConnection方法可以为连接配置参数,如下代码:

var connection = mysql.createConnection({
    host : 'localhost',
    port : 3306,
    database : 'myweb',
    user : 'myroot',
    password : 'myroot'
});

如果还需要其他connection option配置,可以参考下面:

  host:主机地址 (默认:localhost)
  user:用户名
  password:密码
  port:端口号 (默认:3306)
  database:数据库名
  charset:连接字符集(默认:’UTF8_GENERAL_CI’,注意字符集的字母都要大写)
  localAddress:此IP用于TCP连接(可选)
  socketPath:连接到unix域路径,当使用 host 和 port 时会被忽略
  timezone:时区(默认:’local’)
  connectTimeout:连接超时(默认:不限制;单位:毫秒)
  stringifyObjects:是否序列化对象(默认:’false’ ;与安全相关https://github.com/felixge/node-mysql/issues/501)
  typeCast:是否将列值转化为本地JavaScript类型值 (默认:true)
  queryFormat:自定义query语句格式化方法 https://github.com/felixge/node-mysql#custom-format
  supportBigNumbers:数据库支持bigint或decimal类型列时,需要设此option为true (默认:false)
  bigNumberStrings:supportBigNumbers和bigNumberStrings启用 强制bigint或decimal列以JavaScript字符串类型返回(默认:false)
  dateStrings:强制timestamp,datetime,data类型以字符串类型返回,而不是JavaScript Date类型(默认:false)
  debug:开启调试(默认:false)
  multipleStatements:是否许一个query中有多个MySQL语句 (默认:false)
  flags:用于修改连接标志,更多详情:https://github.com/felixge/node-mysql#connection-flags
  ssl:使用ssl参数(与crypto.createCredenitals参数格式一至)或一个包含ssl配置文件名称的字符串,目前只捆绑Amazon RDS的配置文件

当参数配置完成后,我们就可以通过配置好的connection对象进行数据库的连接,

connection.connect(function(err){});

当连接数据库成功之后,我们就可以对数据库进行操作了,即connection下边的query方法(这里注意,操作语句需要在创建好连接的回调函数中)

connection.query(sql,[params],callback);

它接受三个参数,第一个是SQL语句,但是要注意,当传变量的时候要用‘?’代替,不要使用字符串拼接;第二个参数就是按照参数一中‘?’的顺序将变量排列的数组;第三个参数就是回调函数,返回进行数据操作后的数据或者影响;(也可以传两个参数,SQL语句和回调函数,但是这种方法不安全,同时会让SQL语句过于复杂,所以我们一般不推荐使用)

4、关闭连接

同样是connection下边的方法,有两种关闭方式,第一种是c

onnection.end(function(err){});

可以接受关闭连接后的回调函数;第二种是

connection.destroy();

此方法与第一种的区别就是没有回调,直接销毁连接;

5、 基本方法学到了之后,我们就可以自己封装一个模块,供外部调用方便了

A,首先,我们需要在创建一个mysql连接的配置模块(用于进行数据库的链接和数据的操作);代码部分分别如下:

var mysql  = require('mysql');//导入mysql
var db = {};
var host = {//创建连接信息
    host     : 'localhost',//主机名
    user     : 'root',//用户
    password : 'root',//密码
    database : 'cs',//数据库表
    port     : '3306' ,//端口,可不填,默认就是3306
};
//创建对外接口
db.query = function(sql,params,callback){
    //每次使用的时候需要创建链接,数据操作完成之后要关闭连接
    var connection = mysql.createConnection(host);
    connection.connect(function(err){
        if(err){
            console.log('数据库链接失败');
            throw err;
        }
    });
    //开始数据操作
    connection.query( sql, params, function(err,results,fields ){
        if(err){
            console.log('数据操作失败');
            throw err;
        }
        //将查询出来的数据返回给回调函数,这个时候就没有必要使用错误前置的思想了,因为我们在这个文件中已经对错误进行了处理,如果数据检索报错,直接就会阻塞到这个文件中
        callback && callback(results, fields);
        //results作为数据操作后的结果,fields作为数据库连接的一些字段,大家可以打印到控制台观察一下
        //停止链接数据库,必须再查询语句后,要不然一调用这个方法,就直接停止链接,数据操作就会失败
        connection.end(function(err){
            if(err){
                console.log('关闭数据库连接失败!');
                throw err;
            }
        });
    });
};
module.exports = db;

B、封装好了自定义模块之后,我们就可以在需要的地方轻松调用了,这个时候,你就会感觉到刚才做的工作是真的管用,以下是调用实例:

var db = require('./../model/db');  //引入刚才自定义的模块
//对数据库操作(从show_cascade 表中检索所有字段,并打印出结果)
db.query('select  from biao', [],function(results,fields){
    console.log(results);
    console.log(fields);
});

如果不是用上述方法连接的数据库,你可能会遇见,第一次访问首页的时候,连接数据库正常,第二次访问首页,数据库连接不上了,会报错说连接丢失node.js的”Cannot enqueue Handshake after invoking quit”错误,而造成这个错误的原因是:数据库的连接对象被设计成一挂掉就无法重连。

下面展示错误连接造成的第二次无法访问:

var mysql  = require('mysql');//导入mysql
var db = {};
var connection = mysql.createConnection({//创建连接信息
    host     : 'localhost',//主机名
    user     : 'root',//用户
    password : 'root',//密码
    database : 'cs',//数据库表
    port     : '3306' ,//端口,可不填,默认就是3306
    useConnectionPooling: true
});

connection.connect(function(err){//判断是否连接成功,不成功打印失败信息
    if(err){
        console.log(err);
        return;
    }
});//连接数据库
//创建对外接口
db.query = function sqlback(sqllan,fn){
    console.log('123');
    var sql = sqllan;
    if(!sql)return;
    connection.query(sql,function(err,row,fields){
        if(err){
            console.log(err);
            return;
        }
        console.log(fields);
        fn(row);
    });
    connection.end(function(err){
        if(err){
            return;
        }else{
            console.log('连接关闭');
        }
    });//关闭连接
};
module.exports = db;

上面这个段代码我们看了一下执行我第一次调用是正常的但是我第二次我们就发现cmd报错了就是上述的Cannot enqueue Handshake after invoking quit错误,我们在外面调用的方式是

var db = require('./../model/db');  //引入刚才自定义的模块
//对数据库操作(从show_cascade 表中检索所有字段,并打印出结果)
db.query('select  from biao',function(results){
    console.log(results);
    console.log(fields);
});

解决方法一、

我们想一下,我们再次刷新的还是要执行一遍db文件,那么我们的连接和第一次调用的连接冲突了,造成上面的现象,所以如果想用的话我们可以把connection.connect();连接数据库语句放到我们每次调用的方法里面这样我们的重复报错调用就解决了!

解决方法二、

利用连接池

var mysql = require('mysql');
// 创建一个数据库连接池
var pool = mysql.createPool({
    connectionLimit: 50,
    host: 'localhost',
    user: 'admin',
    password: '123456',
    database: 'rp-test'
});
// SELECT  FROM users
// 让我们的方法支持两种模式
// 一种是只传入SQL语句和回调函数
// 一种是传入SQL语句、参数数据、回调函数
exports.query = function (sql, P, C) {
    var params = [];
    var callback;
    // 如果用户传入了两个参数,就是SQL和callback
    if (arguments.length == 2 && typeof arguments[1] == 'function') {
        callback = P;
    } else if (arguments.length == 3 && Array.isArray(arguments[1]) && typeof arguments[2] == 'function') {
        params = P;
        callback = C;
    } else {
        throw new Error('对不起,参数个数不匹配或者参数类型错误');
    }
    // 如果用户传入了三个参数,那么就是SQL和参数数组、回调函数
    // 从池子里面拿一个可以使用的连接
    pool.getConnection(function (err, connection) {
        // Use the connection
        connection.query(sql, params, function () {
            // 使用完毕之后,将该连接释放回连接池
            connection.release();
            callback.apply(null, arguments);
        });
    });
};

调用方式:

var express = require('express');
var db = require('./db');
var router = express.Router();
router.get('/',function(req, res, next){
    db.query("select  from app",function(err,result){
        //console.log(result);
        res.send(JSON.stringify (result));
    });
});
module.exports=router;

这样我们就解决了连接mysql数据库的问题!

评论专区