Transaction

Transactionの作成と使用

Connectionを使用してTransactionを作成します。

import {getConnection} from "typeorm";

await getConnection().transaction(async transactionalEntityManager => {
    
});

EntityManagerを使用してTransactionを作成します。

import {getManager} from "typeorm";

await getManager().transaction(async transactionalEntityManager => {
    
});

Transactionを使用する際には非同期で実行する必要があります。

import {getManager} from "typeorm";

await getManager().transaction(async transactionalEntityManager => {
    await transactionalEntityManager.save(users);
    await transactionalEntityManager.save(photos);
    // ...
});

Transactionで作業する際には、getManagerからグローバルマネージャーを使用する場合に問題が発生します。transactionalEntityManagerなどのエンティティマネージャを使用して下さい。 また、グローバルマネージャーを使用してクエリを実行するクラスを使用することもできませんので、提供されたトランザクションエンティティマネージャーを使用して実行する必要があります。

Transactionの分離レベル

トランザクションの分離レベルの指定は、最初にパラメーターとして設定することで実行できます。

import {getManager} from "typeorm";

await getManager().transaction("SERIALIZABLE", transactionalEntityManager => {
    
});

MySQL、Postgres、SQL Serverでは標準の分離レベル(READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE)をサポートしています。

SQliteはデフォルトでSERIALIZABLEに設定していますが、共有キャッシュモードが有効になっている場合は、READ UNCOMMITTEDを使用できます。

Oracleは、READ COMMITTEDおよびSERIALIZABLEのみをサポートします。

トランザクションデコレータ

Transactionデコレータには@Transaction@TransactionManager@ TransactionRepositoryがあります。

@Transaction すべての実行を単一のデータベーストランザクションにラップ

@ TransactionManager トランザクション内でクエリを実行するために使用する必要があるトランザクションエンティティマネージャを提供

@Transaction()
save(@TransactionManager() manager: EntityManager, user: User) {
    return manager.save(user);
}

分離レベルを設定する場合

@Transaction({ isolation: "SERIALIZABLE" })
save(@TransactionManager() manager: EntityManager, user: User) {
    return manager.save(user);
}

@TransactionManagerが提供するマネージャーを使用するか@TransactionRepositoryを使用して、トランザクションリポジトリ(内部でトランザクションエンティティマネージャを使用している)を挿入することもできます。

@Transaction()
save(user: User, @TransactionRepository(User) userRepository: Repository<User>) {
    return userRepository.save(user);    
}

組み込みリポジトリとカスタムリポジトリの両方を使用できます。

Repository TreeRepository MongoRepositoryなど

@TransactionRepository(Entity) entityRepository:Repository <Entity>
@TransactionRepository()customRepository:CustomRepository)

QueryRunner

QueryRunnerは、単一のデータベースの接続を提供します。 トランザクションは、クエリランナーを使用してコントロールされます。 単一のトランザクションは単一のクエリランナーからのみ確立できます。 クエリランナーインスタンスを手動で作成し、それを使用してトランザクションの状態を手動でコントロールできます。

import {getConnection} from "typeorm";

// 接続を取得し、新しいクエリランナーを作成
const connection = getConnection();
const queryRunner = connection.createQueryRunner();

// 新しいクエリランナーを使用して実際のデータベース接続を確立する
await queryRunner.connect();

// クエリランナーで任意のクエリを実行できるようになりました。次に例を示します。
await queryRunner.query("SELECT * FROM users");

// クエリランナーによって作成された接続で動作するエンティティマネージャーにアクセスすることもできます。
const users = await queryRunner.manager.find(User);

// 新しいトランザクションを開く:
await queryRunner.startTransaction();

try {
    
    // このトランザクションでいくつかの操作を実行します。
    await queryRunner.manager.save(user1);
    await queryRunner.manager.save(user2);
    await queryRunner.manager.save(photos);
    
    // トランザクションをコミット
    await queryRunner.commitTransaction();
    
} catch (err) {
    
    // エラーがあるため、変更をロールバックできます
    await queryRunner.rollbackTransaction();
    
} finally {
    
    // 手動で作成されたクエリランナーをリリースする必要があります。
    await queryRunner.release();
}

QueryRunnerでトランザクションを制御するには3つの方法があります。

  • startTransaction

クエリランナーインスタンス内で新しいトランザクションを開始します。

  • commitTransaction

クエリランナーインスタンスを使用して行われたすべての変更をコミットします。

  • rollbackTransaction

クエリランナーインスタンスを使用して行われたすべての変更をロールバックします。