Infinispace Cache:不一致写入并发操作

如何解决Infinispace Cache:不一致写入并发操作

我到处寻找解决此问题的方法,但找不到任何提示

我的应用程序部署在 JBOSS EAP 6.4 上并使用 JDK 1.8 构建。我在独立的 xml 中配置了一个本地 infinispan 缓存:

<subsystem xmlns="urn:jboss:domain:infinispan:1.5">
    <cache-container name="test-cache" default-cache="test-data-cache" jndi-name="java:jboss/infinispan/test-cache" statistics-enabled="true">
        <transport lock-timeout="60000"/>
        <local-cache name="test-data-cache" statistics-enabled="true">
            <!-- <transaction locking="pessimistic"/> -->
            <locking isolation="READ_COMMITTED"/>
            <expiration lifespan="3600000"/>
        </local-cache>
    </cache-container>
</subsystem>

我将数据放入缓存中:

package com.comp.test;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import org.apache.commons.collections4.MapUtils;
import org.infinispan.Cache;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class CacheTest {

    @Resource(lookup = "java:jboss/infinispan/test-cache")
    private org.infinispan.manager.CacheContainer container;
    
    public void putData(String k,String v) {
        final Map<String,String> tmap = getDataCache().get(k);
        if (!containsData(k)) {
            final HashMap<String,String> rmap = new HashMap<>();
            rmap.put(k+"_"+v,v); 
            getDataCache().put(k,rmap);
        } else {
            getDataCache().get(k).put(k+"_"+v,v);
        }
    }
    
    public boolean containsData(String k) {
        return getDataCache().containsKey(k);
    }

    private Cache<String,Map<String,String>> getDataCache() {
        return container.getCache("test-data-cache");
    }
}

我有无状态 bean,它同时将数据集合放入缓存中(@Asyncronous 注释)。一旦所有并发操作结束,当我从 Cache 中检索数据时,Cache 总是具有较少数量的值。如果我输入 20 个值,则缓存中仅存在 16 / 17 个值。

在我开始将数据放入该特定密钥的缓存之前,我试图找出是否可以锁定该密钥。但我了解到它是由 Infinispan 内部处理的。我在 SO 上发现了另一个类似的问题。但这个问题也没有答案。 Infinispan cache inconsistency for massive concurrent operations

请告诉我如何确保并发放入 infinispan 本地缓存的数据在最后是一致的。如果您需要更多信息,请告诉我。

解决方法

您有两个可用于悲观锁定的选项:

  1. getDataCache().getAdvancedCache().lock(k)
  2. getDataCache().getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK)

还有第三种选择:改用乐观锁,如果另一个事务修改了密钥,则重试该事务。但这不适用于 @TransactionalAttribute,您必须自己调用 TransactionManager.commit() 并捕获 WriteSkewException

,

我通过@Dan Berindei 提供的提示解决了这个问题。

我将缓存配置更改为:

<subsystem xmlns="urn:jboss:domain:infinispan:1.5">
    <cache-container name="test-cache" default-cache="test-data-cache" jndi-name="java:jboss/infinispan/test-cache" statistics-enabled="true">
        <transport lock-timeout="60000"/>
        <local-cache name="test-data-cache" start="EAGER" batching="false" statistics-enabled="true">
            <locking isolation="SERIALIZABLE" acquire-timeout="5000"/>
            <transaction mode="FULL_XA" locking="PESSIMISTIC"/>
            <expiration lifespan="3600000"/>
        </local-cache>
    </cache-container>
</subsystem>

然后我更新我的代码以在每次调用缓存时锁定密钥:

package com.comp.test;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import org.apache.commons.collections4.MapUtils;
import org.infinispan.Cache;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class CacheTest {

    @Resource(lookup = "java:jboss/infinispan/test-cache")
    private org.infinispan.manager.CacheContainer container;
    
    public void putData(String k,String v) {
        final Map<String,String> tmap = getDataCache().get(k);
        if (!containsData(k)) {
            final HashMap<String,String> rmap = new HashMap<>();
            rmap.put(k+"_"+v,v); 
            getDataCache().put(k,rmap);
        } else {
                 AdvancedCache<String,Map<String,String>> cache = getDataCache().getAdvancedCache();
                cache.lock(k);
            getDataCache().get(k).put(k+"_"+v,v);
        }
    }
    
    public boolean containsData(String k) {
        return getDataCache().containsKey(k);
    }

    private Cache<String,String>> getDataCache() {
        return container.getCache("test-data-cache");
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?