Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9349

一番スマートなNode.js+TypeScript+MySQLの使い方

$
0
0
はじめに 割と久々に Node.js で MySQL に繋ぐプログラムを書いてみたのですが、以前と比べて色々パワーアップしていたので、それらを組み合わせて「現時点のベストプラクティスはこんなんかな?」という感じの検討をしてみました。 多分これが一番スマートだと思います・・・という結論に達したのですが、どうだろうか Node.js はまだ触り始めたばかりなので、ご意見を頂けると幸いです ユーティリティ実装 この辺は好みが分かれるところかもしれませんが、DBアクセス用のユーティリティを作ります。 デザインパターン的にコレがベストかは少し自信がありませんが、Node.js だと流行りのパッケージはちょくちょく変わる(ex: mysql が mysql2 になったり、redisが ioredis になったり...etc)ので、自前コードで一枚噛ませて(ラップして)おいた方が良いと思います。(モノによりけりかもしれませんがインフラストラクチャ関連は特に) 関連パッケージ npm install --save dotenv npm install --save mysql2 npm install --save-dev @types/mysql DBユーティリティ実装 db.ts import mysql from 'mysql2' require('dotenv').config() class DatabaseUtility { private pool: mysql.Pool private queryFormat: any constructor() { this.queryFormat = (query: string, values: Array<string>) => { if (!values) return query return query.replace(/\:(\w+)/g, (txt, key) => { return values.hasOwnProperty(key) ? mysql.escape(values[key]) : txt }) } this.pool = mysql.createPool({ host: process.env.RDB_HOST, user: process.env.RDB_USER, password: process.env.RDB_PASSWORD, database: process.env.RDB_NAME }) } private sendQuery(dbc: mysql.PoolConnection, query: string, option?: any): Promise<any> { return new Promise((resolve, reject) => { dbc.query(query, option, (error, results) => { if (error) { reject({ error: error, query: query }) } else { resolve(results) } }) }) } private async sendQueries(dbc: mysql.PoolConnection, queries: Array<{ query: string, option?: any }>) { for (var i = 0; i < queries.length; i++) { await this.sendQuery(dbc, queries[i].query, queries[i].option) } } query(query: string, option?: any): Promise<any> { return new Promise((resolve, reject) => { this.pool.getConnection((error, dbc) => { if (error || !dbc) { reject(error) } else { dbc.config.queryFormat = this.queryFormat this.sendQuery(dbc, query, option) .then(result => resolve(result)) .catch(error => reject(error)) .finally(() => dbc.release()) } }) }) } queries(queries: Array<{ query: string, option?: any }>): Promise<any> { return new Promise((resolve, reject) => { this.pool.getConnection((error, dbc) => { if (error || !dbc) { reject(error) } else { dbc.config.queryFormat = this.queryFormat this.sendQueries(dbc, queries) .then(result => resolve(result)) .catch(error => reject(error)) .finally(() => dbc.release()) } }) }) } } const db = new DatabaseUtility() export default db 上記のコードは Public Domain としておきます。 要点解説 使い方: DB とアクセスするモジュールで import db from './path/to/db' をして db.query async/await の対応処理は db.query で実装 なので、mysql2/promise ではなく mysql2 をそのまま使用 依存パッケージは少なければ少ないほど良いかなと コネクション管理とか面倒なので上位レイヤーには意識させない db.query の都度 getConnection ~ release している コネクションプールならそれでも性能的に問題無いという想定 ただし、クエリ実行回数がメチャクチャ多いバッチ処理とかでは流石に若干影響があるかも? → なので、念の為 db.queries で 1 回の getConnection で複数クエリ実行できるようにしてます(これ居るん? と思いつつ念の為) SQL エラー時は { query: query, error: error } でエラーになった query とエラーオブジェクトを返す ...ようにしたのですが開発時に出てくる dbc.query のエラーケースの大半は SQL の構文エラーなので reject(new Error(`SQL error: ${query}`)) とかにしちゃって良いかも? テスト 準備 .env ファイル RDB_HOST="localhost" RDB_USER="root" RDB_PASSWORD="password" RDB_NAME="test1" SQL CREATE DATABASE test1; CREATE TABLE test1.table1 ( id BIGINT AUTO_INCREMENT, name TEXT, value INT, KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; コード test.ts import db from './db' (async () => { const item1 = { name: "hoge", value: 1234 } const item2 = { name: "hige", value: 5678 } const item3 = { name: "huga", value: 90 } const sql = "insert into table1 (name, value) values (:name, :value)" await db.query(sql, item1) await db.query(sql, item2) await db.query(sql, item3) return await db.query("select * from table1") })().then((result) => { console.dir(result) }).catch((error) => { console.error(error) }) 実行結果 正常にクエリ select * from table1 の実行結果が表示されました。 % npx ts-node test [ { id: 1, name: 'hoge', value: 1234 }, { id: 2, name: 'hige', value: 5678 }, { id: 3, name: 'huga', value: 90 } ] まとめて実行したい場合 これが必要なのかはイマイチ判断がつかないのですが念の為 await db.queries([ { query: sql, option: item1 }, { query: sql, option: item2 }, { query: sql, option: item3 }, ]) 性能検証してみないとなんともですが、これでどの程度処理が早くなるか次第では、queries は廃止した方がユーティリティのコードがシンプルになって良さげかも? まとめ async/await いいですね

Viewing all articles
Browse latest Browse all 9349

Trending Articles