4

JBossEAP4.3を使用しています。

現在、組み込みのJBossTreeCacheをHibernateの第2レベルのキャッシュとして使用する場合の同時実行戦略のさまざまなオプションを検討しています。私はそれを設定し、ログを調べてキャッシュが機能していることを確認しましたが、実際にどの同時実行戦略が使用され、どのように機能するのかわかりません。

エンティティごとに、注釈に次の「使用法」の値のいずれかを設定でき@Cacheます:、、、、、。NONEREAD_ONLYNONSTRICT_READ_WRITEREAD_WRITETRANSACTIONAL

一方、私のJBossTreeCache構成ファイルでは、キャッシュ全体に対して次のいずれかに設定できます:、、、、、IsolationLevel(または単に使用する)。NONEREAD_UNCOMMITTEDREAD_COMMITTEDREPEATABLE_READSERIALIZABLEOPTIMISTIC

構成オプションを1つずつ調べると、ドキュメントは非常に明確ですが、さまざまなオプションを組み合わせるとどうなるのでしょうか。

たとえば@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)、エンティティを設定したが、NONEとして設定しIsolationLevelた場合、どうなりますJBossTreecacheか?

また、サポートと使用法JBossTreeCacheのみをサポートしていると思いますが、それらを何と組み合わせることができますか?たとえば、を使用するとどうなりますか?NONEREAD_ONLYTRANSACTIONALIsolationLevelNONSTRICT_READ_WRITE

全体として、ここには5x6の異なる組み合わせがあるはずですが、すべてが理にかなっているわけではありません。

誰かが私がこれを整理するのを手伝ってくれる?

4

1 に答える 1

8

分離レベルは難しい問題です。

たとえば@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)、エンティティに対して設定NONEし、IsolationLevelに対して設定するJBossTreecacheとどうなりますか?

ほとんどの場合、本番環境では見つけにくいバグです...読み書きキャッシュを使用すると、本質的にすべての「機能」を備えた分散トランザクションに陥ることを理解する必要があります。

組み合わせについて: オブジェクトが変更されない場合は、Hibernate の読み取り専用キャッシュ設定を使用する必要があります。たとえば、国の辞書の場合。キャッシュ同時実行レベル NONE または READ_ONLY を一緒に使用する必要があります。

キャッシュされたオブジェクトが変更された場合は、厳密でない読み書きを使用する必要がありますが、それはめったに発生せず、競合状態の可能性はわずかです。たとえば、タイムゾーン ディクショナリの場合、タイムゾーンが時折表示または非表示になることがありますが、それは年に数回発生する可能性があります。ここでも、キャッシュ同時実行レベル NONE または READ_ONLY を使用する必要があります。

さて、もっと面白い組み合わせに。

TransactionalHibernate のキャッシュは安全ではありません。Hibernate はキャッシュの更新がトランザクションであると想定しますが、それを保証するものは何もしません。したがって、本格的な外部 XA (分散トランザクション) コーディネーターを使用する必要があり、自分が何をしているのかを本当によく理解していない限り、それは本当に必要ありません。ほとんどの場合、XA マネージャーのサポートには完全な EJB3 コンテナーを使用する必要がありますが、プレーンなサーブレット + Spring でhttp://www.atomikos.com/のような外部トランザクション マネージャーを使用することは可能です。TRANSACTIONAL明らかに、キャッシュを使用する必要があります。

「READ_WRITE」は面白い組み合わせです。このモードでは、Hibernate 自体が軽量の XA コーディネーターとして機能するため、本格的な外部 XA は必要ありません。それがどのように機能するかの簡単な説明:

  1. このモードでは、Hibernate がトランザクション自体を管理します。すべての DB アクションはトランザクション内にある必要があり、自動コミット モードは機能しません。
  2. (トランザクションの存続期間中flush()に複数回表示される場合がありますが、通常はコミットの直前に発生します) の間、Hibernate はセッションを通過し、更新/挿入/削除されたオブジェクトを検索します。次に、これらのオブジェクトは最初にデータベースに保存され、次にキャッシュ内でロックおよび更新されるため、同時トランザクションはそれらを更新したり読み取ったりできません。
  3. その後、トランザクションが (明示的または何らかのエラーにより) ロールバックされた場合、ロックされたオブジェクトは単純に解放され、キャッシュから追い出されるため、他のトランザクションはそれらを読み取り/更新できます。
  4. トランザクションが正常にコミットされると、ロックされたオブジェクトは単純に解放され、他のスレッドが読み書きできるようになります。

ここにはいくつかの細かい点があります。

繰り返し可能な読み取り違反の可能性。トランザクション A (tA) とトランザクション B (tB) が同時に開始され、両方がオブジェクト X をロードし、tA がこのオブジェクトを変更し、tA がコミットされたとします。スナップショット分離を使用する多くのデータベース (Oracle、PostgreSQL、FireBird) では、tB がオブジェクト X を再度要求すると、トランザクションの開始時と同じオブジェクト状態を受け取る必要があります。ただし、READ_WRITE キャッシュはこの条件に違反する可能性があります。そこにはスナップショット分離はありません。Hibernate は、キャッシュされたオブジェクトのタイムスタンプを使用して回避しようとしますが、タイマーの精度が低い (Windows では 15.6 ミリ秒) OS では、一部の競合がすり抜けてしまうことが保証されています。

楽観的な古いオブジェクト バージョンの可能性- Windows での作業が非常に不運で、複数のトランザクションが同じタイムスタンプでコミットされている場合、古いオブジェクト バージョンを取得する可能性があります。

于 2011-02-21T22:21:06.377 に答える