3秒でわかる
Node.js から MySQL を扱うライブラリの Promise 版の入口。await でクエリを書けるので、コールバックの入れ子から抜けられます。
もう少し詳しく
どういうものか
mysql2 は Node.js から MySQL や TiDB へ接続するドライバで、その中の mysql2/promise は、すべての API が Promise を返すように包み直したエントリポイントです。読み込み先を変えるだけで、connection.query(sql, cb) というコールバック形式が await connection.query(sql) に変わります。
戻り値は [rows, fields] という2要素の配列です。ふだん欲しいのは rows だけなので、分割代入で受け取る書き方が定着しています。
なぜ必要か
SQL は「つないで、投げて、結果を受けて、閉じる」という順序のある処理の連続です。コールバックで書くと、この順序がそのまま入れ子の深さになり、エラー処理が各段に散らばります。Promise 版なら try と catch でまとめて受けられ、複数のクエリを直列に並べても読み下せます。
具体例
接続プールを作り、プレースホルダ付きで検索する例です。
import mysql from "mysql2/promise";
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: "shop",
connectionLimit: 10,
});
async function findUser(email) {
const [rows] = await pool.execute(
"SELECT id, name FROM users WHERE email = ?",
[email]
);
return rows[0] ?? null;
}つまずきやすいところ
require("mysql2") のまま await を書いてしまい、rows が undefined になる取り違えが最初の関門です。Promise 版を使うには読み込み先を mysql2/promise にする必要があります。
次に多いのが、[rows] の分割代入を忘れて配列2つ分をそのまま JSON にしてしまうミスです。API のレスポンスにフィールド定義まで混ざります。
プレースホルダの ? に配列やオブジェクトを渡そうとするのも失敗しがちです。IN 句で複数値を渡したいときは query 側の ? 展開を使うか、値の数だけ ? を並べます。execute はプリペアドステートメントなので、値の個数が動く用途には向きません。
似た用語との違い
mysql は旧世代のドライバで、mysql2 はプリペアドステートメントや文字コードの扱いを改善した後継です。ORM の Prisma や Sequelize は、この mysql2 のさらに上に乗って SQL 自体を生成します。SQL を自分で書きたいなら mysql2 が素直です。