読み取り専用操作に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()
を使用できますか?
実際には、トランザクションを読み取り専用としてマークする理由があるかもしれません。
autocommit=true
で動作するだけです。@Transactional(readonly=true)
としてマークすると、SpringはJDBCトランザクションを読み取り専用モードに設定します。したがって、実際にのスコープでDBに書き込むことができるかどうかを指定します。このトランザクション。アーキテクチャが面倒で、一部のチームメンバーが変更クエリを予期しない場所に配置する場合、このフラグは問題のある場所を示します。要約すると-あなたは両方の道を行くことができますが、あなたは結果を理解する必要があります。
すべてのデータベースステートメントは、物理トランザクションのコンテキスト内で実行されます トランザクション境界を明示的に宣言しない場合でも (BEGIN/COMMIT/ROLLBACK)。
トランザクション境界を明示的に宣言しない場合、各ステートメントは個別のトランザクションで実行する必要があります(autocommit
モード)。これにより、環境がスレッドごとの接続を処理できない場合、ステートメントごとに1つの接続を開いたり閉じたりすることさえあります。
サービスを@Transactional
として宣言すると、トランザクション期間全体で1つの接続が提供され、すべてのステートメントがその単一の分離接続を使用します。これは、最初に明示的なトランザクションを使用しないよりもはるかに優れています。
大規模なアプリケーションでは、多数の同時リクエストが発生する可能性があり、 データベース接続の取得リクエスト率を下げる を使用すると、アプリケーション全体のパフォーマンスが確実に向上します。
JPAは、読み取り操作でトランザクションを強制しません。トランザクションコンテキストを開始するのを忘れた場合にのみ、書き込みはトランザクションが必要な例外をスローすることになります。それでも、読み取り専用トランザクションであっても、トランザクション境界を宣言する方が常に優れています(Spring @Transactional
では、読み取り専用トランザクションをマークできるため、パフォーマンスが大幅に向上します)。
トランザクションは実際にデータベースにロックをかけます(優れたデータベースエンジンは適切な方法で同時ロックを処理します)。読み取り専用で使用すると、otherトランザクションがデータを追加してビューの一貫性を失わないようにします。常にトランザクションが必要です(分離レベルを調整することが合理的である場合がありますが、最初はそうしないことをお勧めします)。トランザクション中にDBに書き込まない場合、トランザクションのコミットとロールバックの両方が同じ(そして非常に安価)になります。
幸運なことに、DBに対するクエリがORMによって常に単一のSQLクエリにマップされるような場合、DBの組み込みの自動コミット動作に依存して、explicitトランザクションなしで逃げることができますしかし、ORMは比較的複雑なシステムであるため、実装が実際に行っていることを確認するためにより多くの作業を行わない限り、そのような動作に依存することはまったく安全ではありません。明示的なトランザクション境界の記述は、はるかに簡単です(特に、AOPまたは同様のORM駆動の手法で行うことができれば、Java 7以降ではtry-with-resourcesも使用できます) )。
他のデータベースクライアントが結果セットを変更するデータを書き込みたい場合があるため、データベースが結果セットを追跡し続ける必要があるのは、読み取りのみであるかどうかは関係ありません。
クライアントは何もしなかったとしても、DBはCOMMITまたはROLLBACKの前にトランザクションデータを解放できないため、データを読み取るだけでコミットしないため、巨大なデータベースシステムを強制終了する障害のあるプログラムを見てきました。何時間も。