動かざることバグの如し

近づきたいよ 君の理想に

Node.jsのMySQLでAsync/Awaitで接続する

環境

  • Nodejs 12

やりたいこと

Nodejsを使ってMySQLに接続したい。今どきのasync / awaitを使っていい感じに書きたい。というかコールバック書きたくない

インストール

有名なのは mysql なのだが、mysql2というのもある。

すごく昔にsidorares/nodejs-mysql-nativeがあったが開発終了、mysql2として1からコードを書き直したとのこと。mysqlAPIの互換性があり、派生いわく「パフォーマンスは本家より優れている」とのこと。

せっかくなので今回はmysql2を使ってみる。

接続

async/awaitを使う上でのポイントは、通常の require('mysql2')だとコールバックしか使えないので require('mysql2/promise')でrequireする必要がある。一方promiseでrequireした場合はコールバックは使えない。

以下接続してselectするまでのサンプルコード

const mysql = require('mysql2/promise');

(async () => {
  const connection = await mysql.createConnection(
    {
      host:'127.0.0.1',
      user: 'user',
      password: 'pass',
      database: 'xxxxxx'
    }
  );
  try {
    const sql = 'select * from users limit 10';
    const [rows, fields] = await connection.query('select * from users');
    for (const val of rows) {
      console.log(val.id, val.name);
    }
  } catch(e) {
    console.log(e);
  } finally {
    connection.end();
  }
})();

あとは必ず終了時に connection.end(); をしないと終了されない。

プレースホルダーを使う

SQL中に ? を書き、SQLのあとに値を渡すと自動でエスケープしたSQLを生成して投げてくれる。

const [rows, fields] = await connection.query('select * from users where id = ?', 2);

mysql.formatを使うとどんなSQLが生成されるのか確認できる。

console.log(mysql.format('select * from users where id = ?', 2));
// => select * from users where id = 2

レコードの追加

インサートする場合も同様に書けばおk。特にobjectをそのまま渡すことができる。

const user = {id: 10, name: 'taro'};
const res = await connection.query('INSERT INTO users SET ?', user);
console.log(res);

一括レコードの追加

複数で渡す時は INSERT INTO xxx SET は使えないので INSERT INTO xxx VALUES 構文を使う。一工夫必要で、

const users = [
  {id: 5, name: 'taro'},
  {id: 6, name: 'ziro'}
];
const res = await connection.query(`INSERT INTO users (${Object.keys(users[0])}) VALUES ?`, [users.map(x => Object.values(x))]);
console.log(res);

のようにすると

INSERT INTO users (id,name) VALUES (5, 'taro'), (6, 'ziro')

SQLが発行され無事1回のSQLで2レコードが一括で追加される。

参考リンク