3

Infinispan キャッシュと Atomikos トランザクション マネージャーを中心にアプリケーションを構築しています。同じ JVM 上の 2 つの異なるスレッドで開いているトランザクションに対して、トランザクションの分離が機能していないことがわかりました。

キャッシュは、次のコードを使用してインスタンス化されます。

cacheManager = new DefaultCacheManager();
final Configuration config = new Configuration().fluent().transactionManagerLookup(this.tmLookup).recovery().locking()
    .isolationLevel(IsolationLevel.READ_COMMITTED).build();
this.cacheManager.defineConfiguration("Gruik", config);
this.cache = this.cacheManager.getCache("Gruik");

Withは、configure Atomikos トランザクション マネージャーを返すthis.tmLookup単純な実装です。org.infinispan.transaction.lookup.TransactionManagerLookup

キャッシュに 1 つの値を入力して簡単なテストをセットアップし、2 つのスレッドでリーダーとライターをそれぞれ別のトランザクションで起動します。基本的に、ライターはキャッシュに保存されている値を取得し、値を変更してキャッシュに保存します。一方、 get を使用した読み取りは、さまざまな段階で値を表示します: ライターによって変更が行われる前、ライターが pojo を変更した後、ライターが更新された pojo を保存した後、最後にライターのトランザクションのコミット後.

ライターのコードは次のとおりです。

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void performTrans() throws InterruptedException, BrokenBarrierException {
    LOGGER.info("Wait to start");
    pBarrier.await(); // 1
    final Pojo entity = cache.get(KEY);
    LOGGER.info("Start entity: {}", entity);
    pBarrier.await(); // 2
    entity.setValue(entity.getValue() + 42);
    LOGGER.info("Entity changed wait for reader");
    pBarrier.await(); // 3
    cache.put(KEY, entity);
    LOGGER.info("Entity saved wait for reader");
    pBarrier.await(); // 4
}

リーダーコードは次のとおりです。

public void performTrans() throws InterruptedException, BrokenBarrierException {
    LOGGER.info("Wait to start");
    pBarrier.await(); // 1
    final Pojo entity = cache.get(KEY);
    LOGGER.info("Start entity: {}", entity);
    pBarrier.await(); // 2
    LOGGER.info("Wait writer to make changes");
    pBarrier.await(); // 3
    LOGGER.info("After change: {}", entity);
    pBarrier.await(); // 4
    Pojo newEntity = cache.get(KEY);
    LOGGER.info("After save: {}", newEntity);
    pBarrier.await(); // 5
    newEntity = cache.get(KEY);
    LOGGER.info("After transaction end: {}", newEntity);
}

キャッシュから返されたエンティティを追跡するために、Pojoを次のtoString()ように実装しました。

public String toString() {
    return "[" + System.identityHashCode(this) + "] id: " + this.id + ", value: " + this.value;
}

キャッシュが分離されるように構成されているため、リーダーとライターの間に異なる pojo インスタンスがあり、ライターのトランザクションがコミットされた後にのみ変更のみが表示されると予想しました。

ただし、次の出力が得られました。

[Reader] - Wait to start
[Writer] - Wait to start
[Writer] - Start entity: [19682788] id: 1, value: 666
[Reader] - Start entity: [19682788] id: 1, value: 666
[Reader] - Wait writer to make changes
[Writer] - Entity changed wait for reader
[Reader] - After change: [19682788] id: 1, value: 708
[Writer] - Entity saved wait for reader
[Reader] - After save: [19682788] id: 1, value: 708
[Reader] - After transaction end: [19682788] id: 1, value: 708

基本的に、キャッシュは両方のスレッドに同じ pojo インスタンスを返すため、ハッシュマップのように機能します。

質問は:構成または予想される動作で何かを見逃していませんか?

Atomikos から、リーダーとライターの両方で個別のトランザクションの開始を示すログ メッセージを取得できるため、トランザクション マネージャーが機能していることは確かです。

ただし、Infinispan の代わりに Ehcache を使用して同じテストを試みたところ、期待どおりの結果が得られました。2 つのテストのログを比較すると、Infinispan のトランザクション ID がないことだけが明らかな違いである同様のメッセージが見つかりました。

INFO  atomikos  - addParticipant [...]

INFO  atomikos ehcache-txid=0 - addParticipant
4

0 に答える 0