我正在圍繞Infinispan緩存和Atomikos事務管理器構建應用程序。我發現事務隔離不適用於在同一個JVM上的兩個不同線程中打開的事務。與Infinispan在同一進程中的隔離
的緩存使用下面的代碼實例化:
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
返回配置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;
}
由於緩存配置爲隔離,我預計會有不同t閱讀者和作者之間的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
所以基本上,緩存執行像一個HashMap,因爲它返回兩個線程在同一POJO實例。
問題是:我錯過了配置中或預期的行爲?
我很確定事務管理器正在工作,因爲我可以從Atomikos獲得日誌消息,指示讀寫器上的不同事務的開始。
但是我嘗試了使用Ehcache而不是Infinispan的相同測試,並且得到了預期的結果。兩次測試之間的日誌比較,我發現了類似消息的唯一明顯的區別是對的Infinispan沒有事務ID:
INFO atomikos - addParticipant [...]
VS
INFO atomikos ehcache-txid=0 - addParticipant
我試過了,行爲仍然不正確。即:兩個事務中返回的對象仍然相同。 – gabuzo
即使使用討論中提供的參數,Infinispan也沒有執行copyOnRead或copyOnWriter的問題確實存在問題。問題https://issues.jboss.org/browse/ISPN-1345跟蹤此問題。 – gabuzo