3

我正在围绕 Infinispan 缓存和 Atomikos 事务管理器构建应用程序。我发现事务隔离不适用于在同一 JVM 上的两个不同线程中打开的事务。

使用以下代码实例化缓存:

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");

Withthis.tmLookuporg.infinispan.transaction.lookup.TransactionManagerLookup返回配置 Atomikos 事务管理器的简单实现。

我通过使用单个值填充缓存来设置一个小测试,然后在两个线程中启动一个读取器和一个写入器,每个线程都在一个单独的事务中。基本上,写入器将获取存储在缓存中的值,更改值并将其保存到缓存中。另一方面,使用 get 读取并在不同阶段显示值:在 writer 执行任何更改之前,在 writer 更改 pojo 之后,在 writer 保存更新的 pojo 之后,最后在 writer 事务提交之后.

编写器代码是:

@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 获取日志消息,指示读取器和写入器上不同事务的开始。

但是,我使用 Ehcache 而不是 Infinispan 尝试了相同的测试,得到了预期的结果。比较两个测试之间的日志,我发现了类似的消息,唯一明显的区别是 Infinispan 没有事务 ID:

INFO  atomikos  - addParticipant [...]

对比

INFO  atomikos ehcache-txid=0 - addParticipant
4

0 回答 0