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


106

読み取り専用操作で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()か?


9
トランザクションはDB自体に必要です。自動コミットモードについては、community.jboss.org
wiki /…

私は、我々は唯一の書き込み操作のためのtranscationを必要と推測@BheshGurung
user93796

4
リンクの「Decomking auto-commit myths」の部分を読みましたか?
Bhesh Gurung、2012

回答:


131

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

  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 afairがトランザクションをコミットします)。これは、接続プールレベルで構成することもできます(たとえば、C3P0には、デフォルトでロールバックなどのオプションがあります)。
  5. Hibernateに関しては、Springは読み取り専用トランザクションの場合、FlushModeをMANUALに設定します。これにより、ダーティチェックの必要がないなど、他の最適化が行われます。
  6. トランザクション分離レベルをオーバーライドまたは明示的に設定することができます。コミットされていない変更を読み取る、または読み取らない、ファントム読み取りにさらされるなどの理由で、これは読み取りトランザクションにも影響を与えます。

要約すると、両方の方法を使用できますが、結果を理解する必要があります。


私はhibernate(ネイティブhibernate、jpaではありません)を使用していますが、hibernateはdb操作を実行する前にトランザクションを強制的に開始します.1つを開始しないと、アクティブな追跡がないことを示すエラーがスローされます。 、はいの場合はどうですか?
user93796 2012年

readonlyフラグは実際にはトランザクション自体ではなく接続用に設定されており、そのようにHibernate経由でアクセスすることはできません。Spring Transactionサポートを使用し、アノテーションまたはXMLベースのトランザクション構成を使用する必要があります。これにより、SpringはHibernateの代わりに接続とトランザクション管理の所有権を取得します。
Stanislav Bashkyrtsev

1
とてもよく説明されました!Mark Richardsによる別の記事は、トランザクションアノテーション(ibm.com/developerworks/java/library/j-ts1/index.html)の読み取り専用フラグの落とし穴をかなりよく説明しています。
Mahesh

47

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

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

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

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

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


1
「...各ステートメントは、個別のトランザクションで実行する必要があります」。コンテナは自動的にバッチ処理を行いませんか?
Arash

バッチ処理は変更用であり、データの読み取り用ではありません。それでも、JPAとHibernateを使用する場合、JDBCバッチ処理はデフォルトでは有効になっていません。
Vlad Mihalcea

1
Vladに感謝します。私はあなたの記事のいくつかを読みました。彼らは本当に便利です。
アラッシュ

このstackoverflow.com/q/34797480/179850は、読み取り専用トランザクションには大きなパフォーマンス上の利点があるというあなたの肯定とは少し矛盾しているようです。少なくとも、休止状態の場合はそうではないようです。
ニマイ

いいえ、ありません。それは読み取り専用に設定することですが、私の場合は自動コミットを回避することです。
Vlad Mihalcea

17

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

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


14

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.