Infinispan 9.4事务beforeCompletion阶段执行put操作失败如何解决?
问题场景
使用Infinispan 9.4,缓存配置如下:
<local-cache name="localCache"> <locking isolation="READ_COMMITTED"/> <transaction mode="BATCH"/> <memory> <object strategy="NONE"/> </memory> </local-cache>
在事务的beforeCompletion阶段执行缓存写入操作:
tx.registerSynchronization(new Synchronization() { // 省略其他方法实现 public void beforeCompletion() { cache.put(CACHE_KEY, value); } }
执行后抛出UnsupportedOperationException,核心异常栈如下:
ERROR impl.InvocationContextInterceptor - ISPN000136: Error executing command PutKeyValueCommand on Cache 'localCache', writing keys [storage] java.lang.UnsupportedOperationException: null at org.infinispan.commons.util.ImmutableListCopy.add(ImmutableListCopy.java:124) ~[infinispan-commons-9.4.24.Final.jar:9.4.24.Final] at org.infinispan.transaction.impl.LocalTransaction.addModification(LocalTransaction.java:66) ~[infinispan-core-9.4.24.Final.jar:9.4.24.Final] at org.infinispan.interceptors.impl.TxInterceptor.lambda$handleWriteCommand$8(TxInterceptor.java:414) ~[infinispan-core-9.4.24.Final.jar:9.4.24.Final] // 其余栈信息省略
非beforeCompletion阶段执行该写入操作正常,但业务要求必须在该阶段完成此操作,需解决该异常。
解决方案
根因
缓存采用BATCH事务模式时,Infinispan会在事务提交流程早期将事务的修改列表转换为不可变集合(ImmutableListCopy),此时在beforeCompletion阶段尝试添加新修改,会触发不可变集合的add操作不支持异常。
可行解决方式
1. 切换事务模式
将缓存事务模式从BATCH改为NON_XA或LOCAL,这两种模式下事务修改列表在beforeCompletion阶段仍保持可变:
<local-cache name="localCache"> <locking isolation="READ_COMMITTED"/> <transaction mode="NON_XA"/> <!-- 或 LOCAL --> <memory> <object strategy="NONE"/> </memory> </local-cache>
2. 在beforeCompletion中启动独立事务
若必须保留BATCH模式,可在beforeCompletion中挂起当前事务,启动新事务执行缓存写入,完成后恢复原事务:
public void beforeCompletion() { TransactionManager tm = TransactionManagerLookup.getTransactionManager(); Transaction suspendedTx = null; try { suspendedTx = tm.suspend(); tm.begin(); cache.put(CACHE_KEY, value); tm.commit(); } catch (Exception e) { // 异常处理,如日志记录 e.printStackTrace(); } finally { if (suspendedTx != null) { try { tm.resume(suspendedTx); } catch (Exception e) { e.printStackTrace(); } } } }
注意:新事务的提交结果与原事务独立,需自行处理新事务的异常情况。
3. 预注册修改到原事务
调整业务逻辑,在进入beforeCompletion之前,将需要写入的操作提前加入原事务,避免在提交阶段修改事务状态。
内容的提问来源于stack exchange,提问作者Denis Abramov
相关产品推荐
相关产品推荐

