node.js(TypeScript) でMySQL
node.js(TypeScript) でMySQL:
node.jsでMySqlのDBを操作する機会があったので備忘録としてまとめます。
完全に好みが分かれると思いますが、TypeScriptで書きたくなりました。
DB操作は非同期処理になります。
TypeScriptで
nodeでのMySQL操作はこちらを利用しました。
https://github.com/mysqljs/mysql
基本的なDB操作は公式のとおりなので割愛しますが、
複数の更新操作をする場合、前の更新が終わってから次の更新を行う必要があると思います。
先ほど下準備した
下の3行追加することで解決しました。
※TypeScriptだとコンパイルのときに型のエラーがでたのでスルーしてもらうために
すごくしょうもないですが、
forEachの中でasync functionをつかっても、Promiseのリターンを待たずにつぎにいってしまいます。
forEach自体にasyncとかつけても変わりません。
おとなしくfor文を使いました。
nodeでMySQLですが、挿入したレコードのidを取得して別のレコードのカラムを更新するのが楽にできて便利でした。
トランザクションロールバックの処理まで記事にしようと思いましたが、長くなったので書いたコードだけ上げておきます。
node.jsでMySqlのDBを操作する機会があったので備忘録としてまとめます。
まずTypeScriptのコンパイル環境をつくる
完全に好みが分かれると思いますが、TypeScriptで書きたくなりました。npm i -g typescript npm i -g tsc
下準備
DB操作は非同期処理になります。TypeScriptで
async/await
が使えるようにしておきます。tsconfig.json
{ "compilerOptions": { "lib": ["es2015"] }
mysqljs
nodeでのMySQL操作はこちらを利用しました。https://github.com/mysqljs/mysql
npm i --save mysql @types/mysql
ハマりポイント
非同期処理
基本的なDB操作は公式のとおりなので割愛しますが、複数の更新操作をする場合、前の更新が終わってから次の更新を行う必要があると思います。
先ほど下準備した
async/await
の出番、と思ってこう書きました。index.ts
import * as mysql from 'mysql'; // DB接続情報を定義 export interface DbConfig { host: string; user: string; password: string; database: string; } const dbConfig: DbConfig = { host: 'HOST_NAME', user:'USER_NAME', password:'PW', database:'DB' }; // 接続 const pool = mysql.createPool(dbConfig); /** INSERT用のasync関数 */ async function insertRecord(tableName: string, data: any) { try { const sql: string = mysql.format(`INSERT INTO ${tableName} SET ?`, data); return await pool.query(sql) as any; } catch (err) { pool.end(); throw new Error(err); } } (async () => { try{ // 挿入するレコードを準備 const insertRecord: any = { name: 'hoge' }; // 挿入処理 const result = await insertRecord('TABLE_NAME', insertRecord); // 挿入結果のレコードIDをコンソール出力 console.log(result.insertId); pool.end(); } catch (err) { pool.end(); throw new Error(err); } })();
でも結果は、レコードは挿入されますが、コンソール出力はされませんでした。
原因
mysqljsライブラリのpool.query
がPromiseを返してくれない
pool.query
はPromiseを返してくれないので、非同期処理が終わっても待ち状態のままになります。下の3行追加することで解決しました。
index.ts
import * as util from 'util'; const pool = mysql.createPool(dbConfig); // @ts-ignore pool.query = util.promisify(pool.query);
pool.query = util.promisify(pool.query);
とすることで、 Promise
を返すように上書きしています。※TypeScriptだとコンパイルのときに型のエラーがでたのでスルーしてもらうために
@ts-ignore
を1行上に追加しています。
そのほかのハマりポイント
TypeScriptのビルド
すごくしょうもないですが、 index.ts
にいろいろ書いて、下記のようにファイル名を指定してビルドを実行するとtsconfig.json
の内容が反映されません。# ファイル指定はだめ tsc index.ts # OK tsc
forEachはPromiseをみてくれない
forEachの中でasync functionをつかっても、Promiseのリターンを待たずにつぎにいってしまいます。forEach自体にasyncとかつけても変わりません。
おとなしくfor文を使いました。
最後に
nodeでMySQLですが、挿入したレコードのidを取得して別のレコードのカラムを更新するのが楽にできて便利でした。トランザクションロールバックの処理まで記事にしようと思いましたが、長くなったので書いたコードだけ上げておきます。
index.ts
/** * INSERT,UPDATE,DELETEなど、 * エラー時のTransaction Rollbackを必要とするsqlの発行に使用 */ async function editRecordOfTransactionRollback(sql: string) { console.log(sql); return await new Promise((resolve => { pool.getConnection((err, connection) => { if (err) { connection.release(); pool.end(); throw err; } connection.beginTransaction(err1 => { if (err1) { connection.release(); pool.end(); throw err1; } connection.query(sql, (error, results) => { if (error) { connection.rollback(() => { connection.release(); pool.end(); throw error; }); } else { connection.commit((err2 => { if (err2) { connection.rollback(() => { connection.release(); pool.end(); throw err2; }); } else { connection.release(); resolve(results); } })); } }); }); }); })) as Promise<any>; }
コメント
コメントを投稿