通过node-mysql搭建Windows+Node.js+MySQL环境的教程


Posted in Javascript onMarch 01, 2016

前言

MySQL是一款常用的开源数据库产品,通常也是免费数据库的首选。查了一下NPM列表,发现Nodejs有13库可以访问MySQL,felixge/node-mysql似乎是最受关注项目,我也决定尝试用一下。

要注意名字,”felixge/node-mysql”非”node-mysql”,安装部分会介绍这个小插曲!

目录

  • node-mysql介绍
  • 建立MySQL测试库
  • node-mysql安装
  • node-mysql使用

1. node-mysql介绍

felixge/node-mysql是一个纯nodejs的用javascript实现的一个MySQL客户端程序。felixge/node-mysql封装了Nodejs对MySQL的基本操作,100% MIT公共许可证。

项目地址:https://github.com/felixge/node-mysql

2. 建立MySQL测试库

本地创建MySQL测试库:nodejs

~ mysql -uroot -p
mysql> CREATE DATABASE nodejs;
mysql> SHOW DATABASES;
+--------------------+
| Database      |
+--------------------+
| information_schema |
| mysql       |
| nodejs       |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql> GRANT ALL ON nodejs.* to nodejs@'%' IDENTIFIED BY 'nodejs';
mysql> GRANT ALL ON nodejs.* to nodejs@localhost IDENTIFIED BY 'nodejs';

重新登陆MySQL

C:\Users\Administrator>mysql -unodejs -p
Enter password: ******

mysql> SHOW DATABASES;
+--------------------+
| Database      |
+--------------------+
| information_schema |
| nodejs       |
| test        |
+--------------------+
3 rows in set (0.00 sec)

 

mysql> USE nodejs
Database changed

新建一个user表

CREATE TABLE t_user(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(16) NOT NULL ,
create_date TIMESTAMP NULL DEFAULT now()
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX t_quiz_IDX_0 on t_user(name);

 

mysql> SHOW TABLES;
+------------------+
| Tables_in_nodejs |
+------------------+
| t_user      |
+------------------+
1 row in set (0.04 sec)

3. node-mysql安装

我的系统环境

win7 64bit
Nodejs:v0.10.5
Npm:1.2.19
MySQL:Server version: 5.6.11 MySQL Community Server (GPL)
创建工程:nodejs-node-mysql

~ D:\workspace\javascript>mkdir nodejs-node-mysql
~ D:\workspace\javascript>cd nodejs-node-mysql
~ D:\workspace\javascript\nodejs-node-mysql>npm install node-mysql
node-mysql@0.2.0 node_modules\node-mysql
├── better-js-class@0.1.2
├── cps@0.1.7
├── underscore@1.5.2
└── mysql@2.0.0-alpha9 (require-all@0.0.3, bignumber.js@1.0.1)

这里有一个小插曲

安装“node-mysql”后,打开package.json文件发现,这个项目地址是

https://github.com/redblaze/node-mysql.git
从依赖关系可以看到,它依赖于mysql库,是对felixge/node-mysql的封装。

node-mysql1

由于这个项目star是0,fork也是0. 所以,我也不准备花时间测试了,重新安装felixge/node-mysql的包。

重新安装node-mysql

~ D:\workspace\javascript\nodejs-node-mysql>rm -rf node_modules
~ D:\workspace\javascript\nodejs-node-mysql>npm install mysql@2.0.0-alpha9
npm http GET https://registry.npmjs.org/mysql/2.0.0-alpha9
npm http 200 https://registry.npmjs.org/mysql/2.0.0-alpha9
npm http GET https://registry.npmjs.org/mysql/-/mysql-2.0.0-alpha9.tgz
npm http 200 https://registry.npmjs.org/mysql/-/mysql-2.0.0-alpha9.tgz
npm http GET https://registry.npmjs.org/require-all/0.0.3
npm http GET https://registry.npmjs.org/bignumber.js/1.0.1
npm http 304 https://registry.npmjs.org/require-all/0.0.3
npm http 304 https://registry.npmjs.org/bignumber.js/1.0.1
mysql@2.0.0-alpha9 node_modules\mysql
├── require-all@0.0.3
└── bignumber.js@1.0.1

这回就对了,继续下面的开发!

创建node程序启动文件:app.js

第一个测试

~ vi app.js
var mysql = require('mysql');
var conn = mysql.createConnection({
  host: 'localhost',
  user: 'nodejs',
  password: 'nodejs',
  database:'nodejs',
  port: 3306
});
conn.connect();
conn.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
  if (err) throw err;
  console.log('The solution is: ', rows[0].solution);
});
conn.end();

运行node

~ D:\workspace\javascript\nodejs-node-mysql>node app.js
The solution is: 2

这样我们就让Nodejs连接上了MySQL。

4. node-mysql使用

下面我们要对node-mysql的API进行常用的测试。

表新删改查
连接池配置
MySQL断线重连
连接池超时测试
1). 表新删改查
修改app.js

~ vi app.js
var mysql = require('mysql');
var conn = mysql.createConnection({
  host: 'localhost',
  user: 'nodejs',
  password: 'nodejs',
  database: 'nodejs',
  port: 3306
});
conn.connect();

var insertSQL = 'insert into t_user(name) values("conan"),("fens.me")';
var selectSQL = 'select * from t_user limit 10';
var deleteSQL = 'delete from t_user';
var updateSQL = 'update t_user set name="conan update" where name="conan"';

//delete
conn.query(deleteSQL, function (err0, res0) {
  if (err0) console.log(err0);
  console.log("DELETE Return ==> ");
  console.log(res0);

  //insert
  conn.query(insertSQL, function (err1, res1) {
    if (err1) console.log(err1);
    console.log("INSERT Return ==> ");
    console.log(res1);

    //query
    conn.query(selectSQL, function (err2, rows) {
      if (err2) console.log(err2);

      console.log("SELECT ==> ");
      for (var i in rows) {
        console.log(rows[i]);
      }

      //update
      conn.query(updateSQL, function (err3, res3) {
        if (err3) console.log(err3);
        console.log("UPDATE Return ==> ");
        console.log(res3);

        //query
        conn.query(selectSQL, function (err4, rows2) {
          if (err4) console.log(err4);

          console.log("SELECT ==> ");
          for (var i in rows2) {
            console.log(rows2[i]);
          }
        });
      });
    });
  });
});

//conn.end();

控制台输出:

D:\workspace\javascript\nodejs-node-mysql>node app.js
DELETE Return ==>
{ fieldCount: 0,
 affectedRows: 2,
 insertId: 0,
 serverStatus: 34,
 warningCount: 0,
 message: '',
 protocol41: true,
 changedRows: 0 }
INSERT Return ==>
{ fieldCount: 0,
 affectedRows: 2,
 insertId: 33,
 serverStatus: 2,
 warningCount: 0,
 message: '&Records: 2 Duplicates: 0 Warnings: 0',
 protocol41: true,
 changedRows: 0 }
SELECT ==>
{ id: 33,
 name: 'conan',
 create_date: Wed Sep 11 2013 12:09:15 GMT+0800 (中国标准时间) }
{ id: 34,
 name: 'fens.me',
 create_date: Wed Sep 11 2013 12:09:15 GMT+0800 (中国标准时间) }
UPDATE Return ==>
{ fieldCount: 0,
 affectedRows: 1,
 insertId: 0,
 serverStatus: 2,
 warningCount: 0,
 message: '(Rows matched: 1 Changed: 1 Warnings: 0',
 protocol41: true,
 changedRows: 1 }
SELECT ==>
{ id: 33,
 name: 'conan update',
 create_date: Wed Sep 11 2013 12:09:15 GMT+0800 (中国标准时间) }
{ id: 34,
 name: 'fens.me',
 create_date: Wed Sep 11 2013 12:09:15 GMT+0800 (中国标准时间) }

由于node的异步的,上面是一个连续的操作,代码会被写的支离破碎。我们可以通过async库对上面代码进行封装,请参考文章:Nodejs异步流程控制Async

2). 连接池配置

增加文件:app-pooling.js

~ vi app-pooling.js
var mysql = require('mysql');
var pool = mysql.createPool({
  host: 'localhost',
  user: 'nodejs',
  password: 'nodejs',
  database: 'nodejs',
  port: 3306
});

var selectSQL = 'select * from t_user limit 10';

pool.getConnection(function (err, conn) {
  if (err) console.log("POOL ==> " + err);

  conn.query(selectSQL,function(err,rows){
    if (err) console.log(err);
    console.log("SELECT ==> ");
    for (var i in rows) {
      console.log(rows[i]);
    }
    conn.release();
  });
});

控制台输出:

D:\workspace\javascript\nodejs-node-mysql>node app-pooling.js
SELECT ==>
{ id: 39,
 name: 'conan update',
 create_date: Wed Sep 11 2013 13:41:18 GMT+0800 (中国标准时间) }
{ id: 40,
 name: 'fens.me',
 create_date: Wed Sep 11 2013 13:41:18 GMT+0800 (中国标准时间) }

3). MySQL断线重连

分别模拟3种错误

a.登陆密码错误
b.数据库宕机
c.数据库连接超时
新增文件:app-reconnect.js

~ vi app-reconnect.js
var mysql = require('mysql');
var conn;
function handleError () {
  conn = mysql.createConnection({
    host: 'localhost',
    user: 'nodejs',
    password: 'nodejs',
    database: 'nodejs',
    port: 3306
  });

  //连接错误,2秒重试
  conn.connect(function (err) {
    if (err) {
      console.log('error when connecting to db:', err);
      setTimeout(handleError , 2000);
    }
  });

  conn.on('error', function (err) {
    console.log('db error', err);
    // 如果是连接断开,自动重新连接
    if (err.code === 'PROTOCOL_CONNECTION_LOST') {
      handleError();
    } else {
      throw err;
    }
  });
}
handleError();

a. 模拟密码错误

修改password: ‘nodejs11'

控制台输出。

D:\workspace\javascript\nodejs-node-mysql>node app-reconnect.js
error when connecting to db: { [Error: ER_ACCESS_DENIED_ERROR: Access denied for user 'nodejs'@'localhost' (using pass
rd: YES)]
 code: 'ER_ACCESS_DENIED_ERROR',
 errno: 1045,
 sqlState: '28000',
 fatal: true }
error when connecting to db: { [Error: ER_ACCESS_DENIED_ERROR: Access denied for user 'nodejs'@'localhost' (using pass
rd: YES)]
 code: 'ER_ACCESS_DENIED_ERROR',
 errno: 1045,
 sqlState: '28000',
 fatal: true }

b. 模拟数据库宕机
正常启动node,然后杀掉mysqld的进程。

控制台输出。

D:\workspace\javascript\nodejs-node-mysql>node app-reconnect.js
db error { [Error: read ECONNRESET]
 code: 'ECONNRESET',
 errno: 'ECONNRESET',
 syscall: 'read',
 fatal: true }

Error: read ECONNRESET
  at errnoException (net.js:884:11)
  at TCP.onread (net.js:539:19)

这个异常,直接导致node程序被杀死!

c. 模拟连接超时,PROTOCOL_CONNECTION_LOST
切换到root账户, 修改MySQL的wait_timeout参数,设置为10毫秒超时。

~ mysql -uroot -p
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

mysql> set global wait_timeout=10;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 10  |
+---------------+-------+
1 row in set (0.00 sec)

修改文件:app-reconnection.js,在最后增加代码

~ vi app-reconnection.js
function query(){
  console.log(new Date());
  var sql = "show variables like 'wait_timeout'";
  conn.query(sql, function (err, res) {
    console.log(res);
  });
}

query();
setInterval(query, 15*1000);

程序会每融15秒,做一次查询。

控制台输出

D:\workspace\javascript\nodejs-node-mysql>node app-reconnect.js
Wed Sep 11 2013 15:21:14 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]
db error { [Error: Connection lost: The server closed the connection.] fatal: true, code: 'PROTOCOL_CONNECTION_LOST' }
Wed Sep 11 2013 15:21:28 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]
db error { [Error: Connection lost: The server closed the connection.] fatal: true, code: 'PROTOCOL_CONNECTION_LOST' }
Wed Sep 11 2013 15:21:43 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]

我们自己的程序捕获了“PROTOCOL_CONNECTION_LOST”异常,并自动的实现了数据库重连。

4). MySQL连接池的超时测试

针对wait_timeout问题,我们再对连接做一下测试。

修改app-pooling.js文件

var mysql = require('mysql');
var pool = mysql.createPool({
  host: 'localhost',
  user: 'nodejs',
  password: 'nodejs',
  database: 'nodejs',
  port: 3306
});

var selectSQL ="show variables like 'wait_timeout'";

pool.getConnection(function (err, conn) {
  if (err) console.log("POOL ==> " + err);

  function query(){
    conn.query(selectSQL, function (err, res) {
      console.log(new Date());
      console.log(res);
      conn.release();
    });
  }
  query();
  setInterval(query, 5000);
});

控制台输出:

D:\workspace\javascript\nodejs-node-mysql>node app-pooling.js
Wed Sep 11 2013 15:32:25 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]
Wed Sep 11 2013 15:32:30 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]
Wed Sep 11 2013 15:32:35 GMT+0800 (中国标准时间)
[ { Variable_name: 'wait_timeout', Value: '10' } ]

连接池,已经解决了自动重连的问题了,后面我们的开发,可以尽量使用pooling的方式。

Javascript 相关文章推荐
使用户点击后退按钮使效三行代码
Jul 07 Javascript
JavaScript 利用StringBuffer类提升+=拼接字符串效率
Nov 24 Javascript
js获取height和width的方法说明
Jan 06 Javascript
js获取dom的高度和宽度(可见区域及部分等等)
Jun 13 Javascript
JavaScript中的Math 使用介绍
Apr 21 Javascript
js数值计算时使用parseInt进行数据类型转换(jquery)
Oct 07 Javascript
jQuery仿Flash上下翻动的中英文导航菜单实例
Mar 10 Javascript
javascript常用的设计模式
Feb 09 Javascript
微信小程序tabBar底部导航中文注解api详解
Aug 16 Javascript
element ui 表格动态列显示空白bug 修复方法
Sep 04 Javascript
基于 vue-skeleton-webpack-plugin 的骨架屏实战
Aug 05 Javascript
关于ckeditor在bootstrap中modal中弹框无法输入的解决方法
Sep 11 Javascript
jquery自定义右键菜单、全选、不连续选择
Mar 01 #Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 #Javascript
详解Wondows下Node.js使用MongoDB的环境配置
Mar 01 #Javascript
安装使用Mongoose配合Node.js操作MongoDB的基础教程
Mar 01 #Javascript
如何使用Bootstrap的modal组件自定义alert,confirm和modal对话框
Mar 01 #Javascript
JavaScript html5 canvas绘制时钟效果
Mar 01 #Javascript
javascript使用Promise对象实现异步编程
Mar 01 #Javascript
You might like
php创建和删除目录函数介绍和递归删除目录函数分享
2014/11/18 PHP
Thinkphp批量更新数据的方法汇总
2016/06/29 PHP
Yii的Srbac插件用法详解
2016/07/14 PHP
php使用curl模拟浏览器表单上传文件或者图片的方法
2018/11/10 PHP
清除网页历史记录,屏蔽后退按钮!
2008/12/22 Javascript
JS中判断null、undefined与NaN的方法
2014/03/24 Javascript
jQuery中关于ScrollableGridPlugin.js(固定表头)插件的使用逐步解析
2014/07/17 Javascript
JavaScript分页功能的实现方法
2015/04/25 Javascript
javascript图片预加载实例分析
2015/07/16 Javascript
原生js实现百叶窗效果及原理介绍
2016/04/12 Javascript
AngularJS入门教程之REST和定制服务详解
2016/08/19 Javascript
jquery文字填写自动高度的实现方法
2016/11/07 Javascript
对比分析Django的Q查询及AngularJS的Datatables分页插件
2017/02/07 Javascript
Node.js中.pfx后缀文件的处理方法
2017/03/10 Javascript
jQuery实现按比例缩放图片的方法
2017/04/29 jQuery
Nodejs之TCP服务端与客户端聊天程序详解
2017/07/07 NodeJs
vue2.0 实现富文本编辑器功能
2019/05/26 Javascript
微信小程序实现弹出菜单动画
2019/06/21 Javascript
微信小程序中插入激励视频广告并获取收益(实例代码)
2019/12/06 Javascript
如何利用JS将手机号中间四位变成*号
2020/09/29 Javascript
PYTHON正则表达式 re模块使用说明
2011/05/19 Python
简单谈谈Python中函数的可变参数
2016/09/02 Python
Python实现html转换为pdf报告(生成pdf报告)功能示例
2019/05/04 Python
Python读取stdin方法实例
2019/05/24 Python
三个python爬虫项目实例代码
2019/12/28 Python
python如何使用Redis构建分布式锁
2020/01/16 Python
Microsoft新加坡官方网站:购买微软最新软件和技术产品
2016/10/28 全球购物
幼儿园中秋节活动方案2013
2014/01/29 职场文书
工作求职自荐信
2014/06/13 职场文书
重阳节简报
2015/07/20 职场文书
聘任书范文大全
2015/09/21 职场文书
婚庆答谢词大全
2015/09/29 职场文书
2016三严三实专题教育活动心得体会
2016/01/06 职场文书
《生物入侵者》教学反思
2016/02/16 职场文书
六年级上册《闻官军收河南河北》的教学设计
2019/11/15 职场文书
只用40行Python代码就能写出pdf转word小工具
2021/05/31 Python