15
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

node.js(TypeScript) でMySQL

Last updated at Posted at 2018-12-23

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>;
}

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?