Express 4 から MySQL に接続してみました。
なお、コードは github にあります。(mysql ブランチに移動しました。)
https://github.com/hoshi-takanori/express-sample/tree/mysql
準備
あらかじめ MySQL に適当なデータベースとユーザーを作っておきます。
$ mysql -u root -p
Enter password: ********
mysql> create database test_db;
mysql> grant all on test_db.* to test_user@localhost;
mysql> set password for test_user@localhost=password('test_password');
mysql> exit
Bye
$
また、テスト用のテーブルとデータを作成します。
create table users (
name varchar(255) primary key,
email text not null
);
insert into users values ('admin', 'admin@example.com');
insert into users values ('user1', 'user1@example.com');
insert into users values ('user2', 'user2@example.com');
$ mysql -u test_user -p test_db
Enter password: test_password
mysql> source sql/table.sql;
mysql> source sql/test_data.sql;
mysql> select * from users;
+-------+-------------------+
| name | email |
+-------+-------------------+
| admin | admin@example.com |
| user1 | user1@example.com |
| user2 | user2@example.com |
+-------+-------------------+
3 rows in set (0.00 sec)
mysql> exit
Bye
$
とりあえず接続
まず、MySQL に接続するためのパッケージを package.json に追加します。
{
...
"dependencies": {
"express": "*",
"jade": "*",
"mysql": "*"
}
}
次に、app.js を編集します。
var express = require('express');
var mysql = require('mysql');
var app = express();
var connection = mysql.createConnection({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'test_user',
password: process.env.DB_PASS || 'test_password',
database: process.env.DB_NAME || 'test_db'
});
...
これで、node app 起動時に MySQL に接続するようになります。
なお、接続先 DB の情報は環境変数で与えることもできます。
#!/bin/sh
export DB_HOST="localhost"
export DB_USER="test_user"
export DB_PASS="test_password"
export DB_NAME="test_db"
node app
DB アクセス
実際に DB にアクセスするには connection の query メソッドを使います。もちろん非同期です。
...
app.get('/users', function (req, res) {
connection.query('select * from users', function (err, rows) {
res.render('users', { title: 'Express Users', users: rows });
});
});
...
doctype html
html
head
meta(charset='utf-8')
title= title
link(rel='stylesheet', href='/css/style.css')
body
h1= title
table(border=1)
tr
th name
th email
- each user in users
tr
td= user.name
td= user.email
...
table {
border-collapse: collapse;
}
th, td {
padding: 4px;
}
接続プール
とりあえずこれで動きますが、某レンタルサーバーで動かした場合、しばらく放っておくとエラーになりました。どうやら MySQL の接続がタイムアウトしてしまうようです。
そこで、接続プール機能を利用することにします。そうすると、接続を自動的にプールして使い回してくれる上に、接続がタイムアウトした場合は自動的に接続プールから削除されるようです。
...
var pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'test_user',
password: process.env.DB_PASS || 'test_password',
database: process.env.DB_NAME || 'test_db'
});
...
app.get('/users', function (req, res) {
pool.query('select * from users', function (err, rows) {
res.render('users', { title: 'Express Users', users: rows });
});
});
...
接続プールとかよく分かってませんが、これでいいのかなぁ。
さらに、プールクラスターなんてものまであるようです。
エラー処理
エラーが発生した場合は next(err); を呼ぶとエラーハンドラが呼ばれます。
なお、エラーハンドラとは app.use() で設定した引数が 4 個の関数のことです。
...
app.get('/users', function (req, res, next) {
pool.query('select * from users', function (err, rows) {
if (err) return next(err);
res.render('users', { title: 'Express Users', users: rows });
});
});
app.use(function (err, req, res, next) {
res.send(500, 'Error: ' + err.message);
});
...
ちなみに、next() の引数は、それを受け取るエラーハンドラが対応している限り、任意のオブジェクトでも大丈夫のようです。
リンク