修改从Ehcache缓存取出的值,原始缓存也被修改了

一、问题现象

在我们的一个项目中通过Spring注解的方式来使用Ehcache,其中使用到的一个方法的返回值是一个List,测试发现,每次使用该方法得到的结果列表数据都有变化(原始数据没有变化,调用的参数没有变化,缓存也没有过期)。

二、问题原因的查找

我们项目中该方法的一个作用是修改列表数据中的对象的一个属性,因此推测是因为从Ehcache缓存中取出的是原始数据的引用,在方法中修改了引用的具体数据导致缓存原始的值被修改了。于是单步调试,发现在第二次从缓存中取出的数据果然是第一次修改后的数据,于是原因定位到。

三、解决方法

  1. 在该方法中,修改数据时不要修改原始数据,首先拷贝出一份数据,在拷贝出来的数据中修改,这样避免了修改原始数据。但这种方法切入的原来的代码,而且如果有其他方法有使用缓存的话也要修改,修改繁琐,因此不推荐。

  2. Ehcache提供copyOnRead="true" copyOnWrite="true"的配置属性,作用是读取或写入数据时不使用原始数据,而使用拷贝数据。但使用该项配置时同时需要配置copyStrategy class属性,作用是提供copy策略。

<cache name="bannerCache" eternal="false" maxElementsInMemory="50"
		overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="300"
		timeToLiveSeconds="300" memoryStoreEvictionPolicy="LFU"  copyOnRead="true" copyOnWrite="true">
		<copyStrategy class="com.netease.silver.service.ehcache.EhcacheCopyStrategy" />
</cache>

参考下面博客实现了copy策略类

http://www.cnblogs.com/resentment/p/5789644.html

public class EhcacheCopyStrategy implements ReadWriteCopyStrategy<Element> {
		@Override  
	    public Element copyForWrite(Element value) {  
	        if(value != null){  
	            Object temp=(Serializable)value.getObjectValue(); 
	            return new Element(value.getObjectKey(),temp);  
	        }  
	        return value;  
	    }  
	    @Override  
	    public Element copyForRead(Element storedValue) {  
	        if(storedValue != null){  
	            Object temp=(Serializable)storedValue.getObjectValue();  
	            return new Element(storedValue.getObjectKey(),storedValue);
	        }  
	        return storedValue;  
	    } 
}

于是再次测试,发现没有生效,取出的数据还是上次修改的数据。于是再次单步调试查找原因,最后定位在copy策略类的实现逻辑中,由于使用Ehcache缓存的方法返回的是列表数据,但是在copy策略类中实现的拷贝是浅拷贝,返回的数据还是原始数据的引用,因此没有生效,于是修改copy策略类,使用深度copy方法:

public class EhcacheCopyStrategy implements ReadWriteCopyStrategy<Element> {
		@Override  
	    public Element copyForWrite(Element value) {  
	        if(value != null){  
	            Object temp=(Serializable)value.getObjectValue(); 
	            try {
				return new Element(value.getObjectKey(),deepCopy(temp));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
	        }  
	        return value;  
	    }  
	    @Override  
	    public Element copyForRead(Element storedValue) {  
	        if(storedValue != null){  
	            Object temp=(Serializable)storedValue.getObjectValue();  
	            try {
				return new Element(storedValue.getObjectKey(),deepCopy(temp));
			} catch (ClassNotFoundException | IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
	        }  
	        return storedValue;  
	    } 
	    
	    private  Object deepCopy(Object src) throws IOException, ClassNotFoundException {  
	        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
	        ObjectOutputStream out = new ObjectOutputStream(byteOut);  
	        out.writeObject(src);  
	      
	        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
	        ObjectInputStream in = new ObjectInputStream(byteIn);  
	        return in.readObject();  
	    }
}

再次测试发现问题解决!

转载于:https://my.oschina.net/hnrpf/blog/1154224

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值