我正在围绕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");
使用this.tmLookup
是org.infinispan.transaction.lookup.TransactionManagerLookup
的简单实现,返回configure Atomikos事务管理器。
我通过使用单个值填充缓存来设置一个小测试,并且我在一个单独的事务中以两个线程启动读取器和写入器。基本上,编写器将获取存储在缓存中的值,更改值并将其保存到缓存中。在另一端,读取并在各个阶段显示值:在编写器执行任何更改之前,在编写器更改了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实例,并且只有在提交了writer的事务之后才能看到更改。
但是我得到了以下输出:
[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
基本上,缓存的执行方式与hashmap相同,因为它为两个线程返回相同的pojo实例。
问题是:我是否遗漏了配置或预期行为中的内容?
我很确定事务管理器正在工作,因为我可以从Atomikos获取日志消息,指示读取器和写入器上的不同事务的开始。
然而,我尝试使用Ehcache而不是Infinispan进行相同的测试,我得到了预期的结果。比较两个测试之间的日志,我发现类似的消息,唯一明显的区别是Infinispan没有事务ID:
INFO atomikos - addParticipant [...]
VS
INFO atomikos ehcache-txid=0 - addParticipant
答案 0 :(得分:3)
在Infinispan equivalent to ehcache's copyOnRead and copyOnWrite
的底部看看Manik Surtani的回答您应该启用storeAsBinary选项以获得正确的行为。