TypeORM のトランザクション処理を利用する

TypeScript ベースの O/R マッパー、TypeORM で実現できる、トランザクション処理を試してみる。

前提とする環境は、前回の記事で紹介した TypeORM + PostgreSQL 環境。

import { createConnection, getManager, getRepository } from 'typeorm';

import dbConfig from './db-config';
import Customer from './entities/customer';

try {
  // DB に接続する
  const connection = await createConnection(dbConfig);
  
  // トランザクションを開始する
  await getManager().transaction(async (transactionalEntityManager) => {
    // この async 関数内で例外が発生すると、実行していた SQL がロールバックされる
    
    // 思い思いに複数の SQL を実行してみたり…
    const newCustomer = new Customer('Neo');
    const savedCustomer = await transactionalEntityManager.save(newCustomer);
    
    const anotherCustomer = new Customer('Another');
    const insertedCustomer = await transactionalEntityManager.save(Customer, anotherCustomer);
    
    // 最後まで正常に終了すればコミットされる
  });
}
catch(error) {
  console.error('Failed To Exec Transaction : ', error);
}

こんな感じ。

getManager().transaction() 内の async 関数内がトランザクションになる。

この中で何らかの例外が発生すると、途中まで実行していた save()insert() 等の SQL はロールバックされる。

SQL 実行に限らず、どんな例外であってもロールバックできるので、例えば複数のテーブルの更新が成功しないとダメな場合だとか、DB 更新と同時にファイルを書き出したいとかいう場合にも使える。

当然ながら、TypeORM が自動的にロールバックしてくれるのは SQL のみなので、DB 操作以外のロールバック処理は自前で catch 句内で行う必要がある。

EntityRepository ではなく TransactionalEntityManager を利用して SQL 実行するところが若干違うので、実装時はちょっとトライアル & エラーが必要かも〜。