Red Hat Training

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

5.2.2. JTA の使用

永続レイヤーがアプリケーションサーバーで実行される場合 (たとえば、JPA セッション Bean の背後で)、エンティティマネージャにより内部的に取得された各データソース接続は自動的にグローバルな JTA トランザクションの一部になります。Hibernate はこの統合に対して 2 つの方針を提供します。
Bean 管理トランザクション (BMT) を使用する場合、コードは以下のようになります。
// BMT idiom
@Resource public UserTransaction utx;
@Resource public EntityManagerFactory factory;

public void doBusiness() {
    EntityManager em = factory.createEntityManager();
    try {

    // do some work
    ...

    utx.commit();
}
catch (RuntimeException e) {
    if (utx != null) utx.rollback();
    throw e; // or display error message
}
finally {
    em.close();
}
JPA コンテナ内の CMT (Container Managed Transactions) を使用して、トランザクション境界はセッション Bean アノテーションまたは配備記述子で設定されます (プログラムで設定されません)。EntityManager はトランザクション完了時に自動的にフラッシュされます (EntityManager を挿入または検索した場合は、自動的に終了します)。EntityManager の使用中に例外が発生した場合は、例外を補足しないときにトランザクションロールバックが自動的に実行されます。EntityManager 例外は RuntimeException であるため、EJB 仕様 (システム例外とアプリケーション例外) ごとにトランザクションがロールバックされます。
Hibernate EntityManager で hibernate.transaction.factory_class を定義することが重要です (つまり、この値をオーバーライドしない)。org.hibernate.transaction.manager_lookup_class も設定することに注意してください。
CMT 環境を使用する場合は、コードの異なる部分で同じエンティティマネージャを使用することもできます。通常は、非管理環境で、ThreadLocal 変数を使用してエンティティマネージャを保持しますが、単一の EJB 要求は異なるスレッド (たとえば、別のセッション Bean を呼び出すセッション) で実行できます。JPA コンテナはユーザーのために永続コンテキストを伝播します。挿入または検索を使用して、JPA コンテナは JTA コンテキスト (存在する場合) にバインドされた同じ永続コンテキストでエンティティマネージャを返すか、新しいエンティティマネージャを作成し、バインドします (「永続コンテキスト伝播」 を参照)。
CMT および JPA コンテナに使用するエンティティマネージャ/トランザクション管理イディオムは以下のように短縮されました。
//CMT idiom through injection
@PersistenceContext(name="sample") EntityManager em;
つまり、管理対象環境で行うべきことは、EntityManager を挿入し、データアクセスを行い、他のことはコンテナに任せることです。トランザクション境界はセッション Bean のアノテーションとデプロイメント記述子で宣言して設定されます。エンティティマネージャと永続コンテキストのライフサイクルはコンテナによって完全に管理されます。
特定の Hibernate ネイティブ API を使用する場合は、after_statement 接続リリースモードに注意する必要があります。JTA 仕様の制限により、Hibernate が終了していない ScrollableResultsscroll() または iterate() によって返された Iterator インスタンスを自動的にクリーンアップすることはできません。ScrollableResults.close() または Hibernate.close(Iterator)finally ブロックから明示的に呼び出すことにより基礎となるデータベースカーソルをリリースする必要があります (当然、ほとんどのアプリケーションでは CMT コードから scroll() または iterate() を使用することを簡単に回避できます)。