web-dev-qa-db-ja.com

読み取り専用操作にHibernateでトランザクションが必要なのはなぜですか?

読み取り専用操作にHibernateでトランザクションが必要なのはなぜですか?

次のトランザクションはDBにロックをかけますか?

DBから取得するコードの例:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

session.close()の代わりにtx.commit()を使用できますか?

91
user93796

実際には、トランザクションを読み取り専用としてマークする理由があるかもしれません。

  1. 読み取り用のトランザクションは実際には奇妙に見えるかもしれず、多くの場合、人々はこの場合トランザクションのメソッドをマークしません。ただし、JDBCはとにかくトランザクションを作成します。異なるオプションが明示的に設定されていない場合は、autocommit=trueで動作するだけです。
  2. ただし、メソッドがデータベースに書き込まないという保証はありません。メソッドを@Transactional(readonly=true)としてマークすると、SpringはJDBCトランザクションを読み取り専用モードに設定します。したがって、実際にのスコープでDBに書き込むことができるかどうかを指定します。このトランザクション。アーキテクチャが面倒で、一部のチームメンバーが変更クエリを予期しない場所に配置する場合、このフラグは問題のある場所を示します。
  3. また、読み取り専用トランザクションはDBによって最適化できますが、これはもちろんDB固有です。例えば。 MySQLは、5.6.4バージョンからInnoDBでのみこのサポートを追加しました。
  4. JDBCを直接使用しておらず、ORMを使用している場合、問題が生じる可能性があります。たとえば、Hibernateコミュニティは、トランザクション外での作業は予測できない動作を引き起こす可能性があると述べています。これは、Hibernateがトランザクションを開くが、それ自体では閉じないため、トランザクションがコミットされていない状態で接続が接続プールに返されるためです。それではどうなりますか? JDBCは沈黙を保つため、これは実装固有です(MySQLはトランザクションをロールバックし、Oracleはそれをコミットします)。これは、接続プールレベルで構成することもできます(たとえば、C3P0はそのようなオプションを提供し、デフォルトでロールバックします)。
  5. Hibernateに関しては、Springは読み取り専用トランザクションの場合にFlushModeをMANUALに設定します。これにより、ダーティチェックの必要がないなど、他の最適化が行われます。
  6. トランザクション分離レベルを明示的にオーバーライドまたは設定できます。これは、コミットされていない変更を読み取ったり、幻の読み取りにさらされたりしたくないため、読み取りトランザクションにも影響します。

要約すると-あなたは両方の道を行くことができますが、あなたは結果を理解する必要があります。

118

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

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

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

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

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

35
Vlad Mihalcea

トランザクションは実際にデータベースにロックをかけます(優れたデータベースエンジンは適切な方法で同時ロックを処理します)。読み取り専用で使用すると、otherトランザクションがデータを追加してビューの一貫性を失わないようにします。常にトランザクションが必要です(分離レベルを調整することが合理的である場合がありますが、最初はそうしないことをお勧めします)。トランザクション中にDBに書き込まない場合、トランザクションのコミットとロールバックの両方が同じ(そして非常に安価)になります。

幸運なことに、DBに対するクエリがORMによって常に単一のSQLクエリにマップされるような場合、DBの組み込みの自動コミット動作に依存して、explicitトランザクションなしで逃げることができますしかし、ORMは比較的複雑なシステムであるため、実装が実際に行っていることを確認するためにより多くの作業を行わない限り、そのような動作に依存することはまったく安全ではありません。明示的なトランザクション境界の記述は、はるかに簡単です(特に、AOPまたは同様のORM駆動の手法で行うことができれば、Java 7以降ではtry-with-resourcesも使用できます) )。

16
Donal Fellows

他のデータベースクライアントが結果セットを変更するデータを書き込みたい場合があるため、データベースが結果セットを追跡し続ける必要があるのは、読み取りのみであるかどうかは関係ありません。

クライアントは何もしなかったとしても、DBはCOMMITまたはROLLBACKの前にトランザクションデータを解放できないため、データを読み取るだけでコミットしないため、巨大なデータベースシステムを強制終了する障害のあるプログラムを見てきました。何時間も。

13
Ingo