EhCache缓存了对象修改

时间:2016-12-23 18:12:54

标签: java caching ehcache ehcache-bigmemory jsr107

我要用EhCache实现缓存。基本要求是,我必须保持该缓存对象的固定间隔(现在在下面的代码中1小时)。所以,我实现了如下代码:

示例域对象:

import lombok.*;
@Getter
@Setter
@ToString
@AllArgsConstructor
public class City implements Serializable {
    public String name;
    public String country;
    public int population;
}

缓存管理器类:

import net.sf.ehcache.*;
public class JsonObjCacheManager {
    private static final Logger logger = LoggerFactory.getLogger(JsonObjCacheManager.class);
    private CacheManager manager;

    private Cache objectCache;

    public JsonObjCacheManager(){
        manager = CacheManager.create();

        objectCache =  manager.getCache("jsonDocCache");

        if( objectCache == null){
            objectCache = new Cache(
                    new CacheConfiguration("jsonDocCache", 1000)
                            .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU)
                            .eternal(false)
                            .timeToLiveSeconds(60 * 60)
                            .timeToIdleSeconds(0)
                            .diskExpiryThreadIntervalSeconds(0)
                            .persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.LOCALTEMPSWAP)));
            objectCache.disableDynamicFeatures();
            manager.addCache(objectCache);
        }
    }

    public List<String> getKeys() { return objectCache.getKeys();}

    public void clearCache(){
        manager.removeAllCaches();
    }

    public void putInCache(String key, Object value){
        try{
            objectCache.put(new Element(key, value));
        }catch (CacheException e){
            logger.error(String.format( "Problem occurred while putting data into cache: %s", e.getMessage()));
        }
    }

    public Object retrieveFromCache(String key){
        try {
            Element element = objectCache.get(key);
            if(element != null)
                return element.getObjectValue();
        }catch (CacheException ce){
            logger.error(String.format("Problem occurred while trying to retrieveSpecific from cache: %s", ce.getMessage()));
        }
        return null;
    }
}

它非常正确地缓存和检索值。但我的要求是,我必须修改我从缓存中检索给定密钥的对象。我得到的是,如果我修改从缓存中检索的对象,那么该密钥的缓存对象也会被修改。

以下是示例:

    public class Application {

        public static void main(String[] args) {
            JsonObjCacheManager manager = new JsonObjCacheManager();

            final City city1 = new City("ATL","USA",12100);
            final City city2 = new City("FL","USA",12000);

            manager.putInCache(city1.getName(), city1);
            manager.putInCache(city2.getName(), city2);

            System.out.println(manager.getKeys());

            for(String key: manager.getKeys()){
                System.out.println(key + ": "+ manager.retrieveFromCache(key));
            }

            City cityFromCache = (City) manager.retrieveFromCache(city1.getName());
            cityFromCache.setName("KTM");
            cityFromCache.setCountry("NPL");
            System.out.println(manager.getKeys());

            for(String key: manager.getKeys()){
                System.out.println(key  + ": "+ manager.retrieveFromCache(key));
            }
        } 
}

我得到的输出是:

[ATL, FL]
ATL: City(name=ATL, country=USA, population=12100)
FL: City(name=FL, country=USA, population=12000)
[ATL, FL]
ATL: City(name=KTM, country=NPL, population=12100)
FL: City(name=FL, country=USA, population=12000)

这意味着,每当我检索和修改给定键的对象时,它也会反映在缓存值中。

我的要求是,不应修改给定密钥的缓存对象。有没有办法实现这个目标?或者它是不是正确的方式来实现EhCache?或者我错过了一些基本原则?

我正在使用EhCache V2.10.3

谢谢!

1 个答案:

答案 0 :(得分:2)

当您使用将数据存储在堆上并使用直接对象引用的缓存时,您需要在使用之前复制该对象。

一般来说,最好不要在将对象引用移交给缓存(或任何超出您控制范围的人)之后改变值。

某些缓存有一个复制机制来保护缓存的值不被修改。例如。在EHCache3中,您可以添加复印机,请参阅Serializers and Copiers

或者,更改您的设计:当您需要改变值时,也许您可​​以将值拆分为两个对象,一个是缓存,一个包含需要变异的数据,后者包含第一个。

相关问题