分離レベルは難しい問題です。
たとえば@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
、エンティティに対して設定NONE
し、IsolationLevel
に対して設定するJBossTreecache
とどうなりますか?
ほとんどの場合、本番環境では見つけにくいバグです...読み書きキャッシュを使用すると、本質的にすべての「機能」を備えた分散トランザクションに陥ることを理解する必要があります。
組み合わせについて: オブジェクトが変更されない場合は、Hibernate の読み取り専用キャッシュ設定を使用する必要があります。たとえば、国の辞書の場合。キャッシュ同時実行レベル NONE または READ_ONLY を一緒に使用する必要があります。
キャッシュされたオブジェクトが変更された場合は、厳密でない読み書きを使用する必要がありますが、それはめったに発生せず、競合状態の可能性はわずかです。たとえば、タイムゾーン ディクショナリの場合、タイムゾーンが時折表示または非表示になることがありますが、それは年に数回発生する可能性があります。ここでも、キャッシュ同時実行レベル NONE または READ_ONLY を使用する必要があります。
さて、もっと面白い組み合わせに。
Transactional
Hibernate のキャッシュは安全ではありません。Hibernate はキャッシュの更新がトランザクションであると想定しますが、それを保証するものは何もしません。したがって、本格的な外部 XA (分散トランザクション) コーディネーターを使用する必要があり、自分が何をしているのかを本当によく理解していない限り、それは本当に必要ありません。ほとんどの場合、XA マネージャーのサポートには完全な EJB3 コンテナーを使用する必要がありますが、プレーンなサーブレット + Spring でhttp://www.atomikos.com/のような外部トランザクション マネージャーを使用することは可能です。TRANSACTIONAL
明らかに、キャッシュを使用する必要があります。
「READ_WRITE」は面白い組み合わせです。このモードでは、Hibernate 自体が軽量の XA コーディネーターとして機能するため、本格的な外部 XA は必要ありません。それがどのように機能するかの簡単な説明:
- このモードでは、Hibernate がトランザクション自体を管理します。すべての DB アクションはトランザクション内にある必要があり、自動コミット モードは機能しません。
- (トランザクションの存続期間中
flush()
に複数回表示される場合がありますが、通常はコミットの直前に発生します) の間、Hibernate はセッションを通過し、更新/挿入/削除されたオブジェクトを検索します。次に、これらのオブジェクトは最初にデータベースに保存され、次にキャッシュ内でロックおよび更新されるため、同時トランザクションはそれらを更新したり読み取ったりできません。
- その後、トランザクションが (明示的または何らかのエラーにより) ロールバックされた場合、ロックされたオブジェクトは単純に解放され、キャッシュから追い出されるため、他のトランザクションはそれらを読み取り/更新できます。
- トランザクションが正常にコミットされると、ロックされたオブジェクトは単純に解放され、他のスレッドが読み書きできるようになります。
ここにはいくつかの細かい点があります。
繰り返し可能な読み取り違反の可能性。トランザクション A (tA) とトランザクション B (tB) が同時に開始され、両方がオブジェクト X をロードし、tA がこのオブジェクトを変更し、tA がコミットされたとします。スナップショット分離を使用する多くのデータベース (Oracle、PostgreSQL、FireBird) では、tB がオブジェクト X を再度要求すると、トランザクションの開始時と同じオブジェクト状態を受け取る必要があります。ただし、READ_WRITE キャッシュはこの条件に違反する可能性があります。そこにはスナップショット分離はありません。Hibernate は、キャッシュされたオブジェクトのタイムスタンプを使用して回避しようとしますが、タイマーの精度が低い (Windows では 15.6 ミリ秒) OS では、一部の競合がすり抜けてしまうことが保証されています。
楽観的な古いオブジェクト バージョンの可能性- Windows での作業が非常に不運で、複数のトランザクションが同じタイムスタンプでコミットされている場合、古いオブジェクト バージョンを取得する可能性があります。