Red Hat Training

A Red Hat training course is available for Red Hat JBoss Web Server

5.2. データベーストランザクション境界

データベース (またはシステム) トランザクション境界は、常に必要です。データベーストランザクションの外部ではデータベースとの通信が起こりません (これにより、自動コミットモードに慣れている多くの開発者が混乱することがあります)。常に、明確なトランザクション境界を (読み取り専用の操作に対しても) 使用してください。これは、分離レベルとデータベース機能によっては必要でないことがあります。ただし、トランザクションの境界を常に明示的に設定する場合、欠点は存在しません。EXTENDED 永続コンテキストの変更を保持する必要がある場合は、トランザクション外で操作を実行する必要があります。
JPA アプリケーションは非管理 (つまり、スタンドアロンで単純な Web または Swing アプリケーション) および管理 J2EE 環境で実行できます。非管理環境では、通常 EntityManagerFactory が独自のデータベース接続プールを担当します。アプリケーション開発者はトランザクション境界を手動で設定する必要があります (つまり、データベーストランザクション自体を開始、コミット、またはロールバックします)。管理環境は、通常コンテナ管理トランザクションを提供します (トランザクションアセンブリは EJB セッション Bean のアノテーションを使用して定義されます)。トランザクション境界のプログラミングは不必要になり、EntityManager のフラッシュも自動的に実行されます。
通常、作業単位の終了には 4 つの異なるフェーズが関係します。
  • (リソースローカルまたは JTA) トランザクションをコミットします (これによりエンティティマネージャと永続コンテキストが自動的にフラッシュされます)。
  • エンティティマネージャを終了します (アプリケーション管理エンティティマネージャを使用している場合)。
  • 例外を処理します。
トランザクション境界と管理および非管理環境での例外処理について詳しく説明します。

5.2.1. 非管理環境

JPA 永続レイヤーが非管理環境で実行される場合、データベース接続は通常目に付かない Hibernate のプールメカニズムによって処理されます。一般的なエンティティマネージャとトランザクション処理イディオムは以下のとおりです。
// Non-managed environment idiom
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try {
    tx = em.getTransaction();
    tx.begin();

    // do some work
    ...

    tx.commit();
}
catch (RuntimeException e) {
    if ( tx != null && tx.isActive() ) tx.rollback();
    throw e; // or display error message
}
finally {
    em.close();
}
EntityManager に対して明示的に flush() を実行する必要はありません。commit() を呼び出すと、自動的に同期が実行されます。
close() を呼び出すと、EntityManager が終了します。close() の主な問題はリソースのリリースです。常に終了し、保証された最終ブロック外部で実行しないでください。
多くの場合、通常のアプリケーションではビジネスコードにこのイディオムが使用されません。重大な (システム) 例外は常に「上部」で補足する必要があります。つまり、エンティティマネージャコール (永続レイヤー) を実行するコードと RuntimeException を処理 (および通常はクリーンアップを実行し、終了します) するコードは異なるレイヤーに属します。これは、設計を行う上で問題となります。できるだけ J2EE/EJB コンテナサービスを使用してください。例外処理については、この章の後半で説明します。

5.2.1.1. EntityTransaction

JTA 環境では、環境のトランザクションと対話するのに特別な API を必要としません。トランザクション宣言または JTA API を使用します。
RESOURCE_LOCAL エンティティマネージャを使用する場合は、EntityTransaction API を使用してトランザクション境界を設定する必要があります。EntityTransaction は、entityManager.getTransaction() を使用して取得できます。この EntityTransaction API は通常の begin() メソッド、commit() メソッド、rollback() メソッド、および isActive() メソッドを提供します。また、トランザクションをロールバックとマークすることもできます (つまり、トランザクションを強制的にロールバックできます)。これは、JTA 操作 setRollbackOnly() に非常に似ています。commit() 操作が失敗した場合やトランザクションが setRollbackOnly() とマークされた場合は、commit() メソッドがトランザクションをロールバックしようとし、javax.transaction.RollbackException を発生させます。
JTA エンティティマネージャでは、entityManager.getTransaction() コールが許可されません。