머리말
MySQL은 일반적으로 사용되는 오픈 소스 데이터베이스 제품이며 일반적으로 무료 데이터베이스 중 가장 먼저 선택됩니다. NPM 목록을 확인해 보니 Nodejs에 MySQL에 액세스할 수 있는 라이브러리가 13개 있는 것으로 나타났습니다. felixge/node-mysql이 가장 인기 있는 프로젝트인 것 같아서 시도해 보기로 했습니다.
주의하세요. "felixge/node-mysql"은 "node-mysql"이 아닙니다. 이번 에피소드는 설치 부분에서 소개됩니다!
목차
1. node-mysql 소개
felixge/node-mysql은 javascript를 사용하여 순수 nodejs로 구현된 MySQL 클라이언트 프로그램입니다. felixge/node-mysql은 100% MIT 공개 라이선스인 MySQL에서 Nodejs의 기본 작업을 캡슐화합니다.
프로젝트 주소: 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
새 사용자 테이블 생성
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 64비트
Nodejs:v0.10.5
Npm:1.2.19
MySQL:서버 버전: 5.6.11 MySQL 커뮤니티 서버(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을 캡슐화한 것입니다.
노드-mysql1
이 프로젝트의 별표는 0이므로 포크도 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
이제, 계속해서 개발해보겠습니다!
노드 프로그램 시작 파일 생성: 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();
노드 실행
~ 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 (中国标准时间) }
노드의 비동기 특성으로 인해 위 작업은 연속적인 작업이므로 코드가 조각으로 작성됩니다. 비동기 라이브러리를 통해 위 코드를 캡슐화할 수 있습니다. Nodejs 비동기 프로세스 제어 비동기
문서를 참조하세요.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. 시뮬레이션 비밀번호가 잘못되었습니다
비밀번호 수정: '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. 데이터베이스 가동 중지 시간 시뮬레이션
노드를 정상적으로 시작한 다음 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)
이 예외로 인해 노드 프로그램이 직접 종료됩니다!
c. 시뮬레이션된 연결 시간 초과, PROTOCOL_CONNECTION_LOST
루트 계정으로 전환하고 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' } ]
연결 풀을 통해 자동 재연결 문제가 해결되었습니다. 이후 개발에서는 풀링을 최대한 활용할 수 있습니다.