web-dev-qa-db-ja.com

データを読み取るためのデータベーストランザクションが必要ですか?

データベースからデータを読み込もうとすると、少なくとも

((Session)em.getDelegate()).createCriteria()

トランザクションが存在しないという例外がスローされます。

注釈を追加すると:

@Transactional(
    value = SomeClass.TRANSACTIONAL_MANAGER, 
    propagation = Propagation.SUPPORTS, 
    readOnly = true
)

それは正常に動作します。

ただし、データにアクセスして読み取るために1秒あたり数百万回の読み取りが発生するため、環境が不必要に詰まらないようにしたいと思います。

そうでない場合、読み取り専用を作成するコストは何ですかPropagation.Supportsトランザクション?

Springと組み合わせて、トランザクションなしでHibernate Criteriaクエリを作成することはできませんか?

25
mmm

すべてのデータベースステートメントは、物理トランザクションのコンテキスト内で実行されます トランザクション境界を明示的に宣言していない場合でも (BEGIN/COMMIT/ROLLBACK)。

トランザクション境界を宣言しない場合は、各ステートメントを個別のトランザクションで実行する必要があります(autocommitモード)。ご使用の環境でスレッドごとの接続バインディングを処理できない場合は、ステートメントごとに1つの接続を開いたり閉じたりすることもできます。

サービスを@Transactionalとして宣言すると、トランザクション期間全体で1つの接続が提供され、すべてのステートメントがその単一の分離接続を使用します。これは、最初に明示的なトランザクションを使用しないよりもはるかに優れています。

大規模なアプリケーションでは、多数の同時要求が発生する可能性があり、 データベース接続取得要求率を下げる は、アプリケーション全体のパフォーマンスを確実に向上させます。

JPAは読み取り操作にトランザクションを強制しません。トランザクションコンテキストの開始を忘れた場合にのみ、書き込みのみがトランザクション必須例外をスローします。それでも、読み取り専用トランザクションの場合でもトランザクション境界を宣言することをお勧めします(Springでは@Transactionalを使用すると、読み取り専用トランザクションにマークを付けることができるため、パフォーマンスが大幅に向上します)。

ここで、宣言的なトランザクション境界(@Transactionalなど)を使用する場合は、JDBCステートメントが実行されるまで、データベース接続の取得を遅らせる必要があります。 JTAでは、これがデフォルトの動作です。 RESOURCE_LOCALを使用する場合は、 hibernate.connection.provider_disables_autocommit 構成プロパティを設定し、基になる接続プールが自動コミットモードを無効にするように設定されていることを確認する必要があります。

96
Vlad Mihalcea

[〜#〜] jpa [〜#〜]の私の経験によると、J2EEトランザクションマネージャを実行するには常に必要です[〜#〜] crud [ 〜#〜]操作の安全性。データの整合性を維持するためにロールバックを保証します。

エンタープライズアプリケーションは、さまざまなリソースを使用してデータを保存し、データベースやメッセージキューなどのメッセージを送信します。これらのリソースを順次クエリして、問題が発生したときに操作全体をキャンセルする場合は、このクエリを作業単位に入れて、全体として実行されるようにする必要があります。

あなたはそれを定義することができます:

  • (質問に示されているように)関連する注釈を使用する。このようにして、コンテナは指定された永続コンテキストのトランザクションマネージャを自動的にロードします。

  • 次のように、トランザクションマネージャを手動で挿入します。

    public class sample {
    
        @PersistenceContext
        EntityManager em;
    
        // Injected transaction manager
        @Inject
        UserTransaction utx;
    
        private static final String[] GAME_TITLES = {
            "Super Mario Brothers",
            "Mario Kart",
            "F-Zero"
        };
    
        private void clearData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Dumping old records...");
            em.createQuery("delete from Game").executeUpdate();
            utx.commit();
        }
    
        private void insertData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Inserting records...");
            for (String title : GAME_TITLES) {
                Game game = new Game(title);
                em.persist(game);
            }
            utx.commit();
            // clear the persistence context (first-level cache)
            em.clear();
        }
    
        // ...
    
    }
    

Spring Dataは、JPA仕様の実装と同じ方法で実行できます。

詳細については、次の記事を参照してください。Java_Persistence/Transactions

1
vdenotaris