Express 4 で MySQL に接続

Express 4 から MySQL に接続してみました。

なお、コードは github にあります。(mysql ブランチに移動しました。)
https://github.com/hoshi-takanori/express-sample/tree/mysql

## 準備

あらかじめ MySQL に適当なデータベースとユーザーを作っておきます。

```shell-session
$ 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
$ 
```

また、テスト用のテーブルとデータを作成します。

```sql/table.sql
create table users (
    name varchar(255) primary key,
    email text not null
);
```

```sql/test_data.sql
insert into users values ('admin', 'admin@example.com');
insert into users values ('user1', 'user1@example.com');
insert into users values ('user2', 'user2@example.com');
```

```shell-session
$ 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 に追加します。

```package.json
{
  ...
  "dependencies": {
    "express": "*",
    "jade": "*",
    "mysql": "*"
  }
}
```

次に、app.js を編集します。

```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 の情報は環境変数で与えることもできます。

```run.sh
#!/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.js
...

app.get('/users', function (req, res) {
  connection.query('select * from users', function (err, rows) {
    res.render('users', { title: 'Express Users', users: rows });
  });
});

...
```

```views/users.jade
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
```

```public/css/style.css
...

table {
  border-collapse: collapse;
}

th, td {
  padding: 4px;
}
```

## 接続プール

とりあえずこれで動きますが、某レンタルサーバーで動かした場合、しばらく放っておくとエラーになりました。どうやら MySQL の接続がタイムアウトしてしまうようです。
そこで、接続プール機能を利用することにします。そうすると、接続を自動的にプールして使い回してくれる上に、接続がタイムアウトした場合は自動的に接続プールから削除されるようです。

```app.js
...

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.js
...

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() の引数は、それを受け取るエラーハンドラが対応している限り、任意のオブジェクトでも大丈夫のようです。

## リンク
https://github.com/felixge/node-mysql