ehcache2拾遗之copyOnRead,copyOnWrite
问题描述
缓存在提升应用性能,提高访问效率上都是至关重要的一步。ehcache也是广为使用的缓存之一。但是如果将一个可变的对象(如普通的POJO/List/Map等)存入缓存中,会导致怎样潜在的问题。下面来看一个例子
//首先创建一个简单的POJO
public class Student {
private String name;
public Student(String name){
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
之后创建一个POJO并使用ehcache来进行缓存
@Test
public void copyOnRead(){
CacheManager cache=CacheManager.create("cache.xml"); //读取cache配置文件,如果不配置ehcache有默认的failsafe配置
Ehcache copyCache=cache.addCacheIfAbsent("copyCache"); //读取名为copyCache的cache,如果没有则创建
Student stu=new Student("张三"); //创建一个简单的POJO
Element el=new Element(1,stu); //将对象放入Element对象
copyCache.put(el); //存入缓存
stu.setName("李四"); //之后改变POJO的内容
Student cachedStu=(Student) copyCache.get(1).getObjectValue();//从缓存中取出对象
System.out.println("cache中取出的对象的名字:"+cachedStu.getName());
System.out.println("cache中取出的对象和源对象相等:"+(copyCache.get(1)==el));
System.out.println("两次cache中取出的对象相等"+(copyCache.get(1)==copyCache.get(1)));
}
以上代码的输出结果是
cache中取出的对象的名字:李四
cache中取出的对象和源对象相等:true
两次cache中取出的对象相等true
可以看到缓存中的对象在外部对象被修改时也被修改了(这里只考虑内存缓存,不考虑序列化到磁盘)。
原因分析
这是由于ehcache中存放的Element对象是直接保存了原对象的引用,所以引用的内容被修改之后cache内部的值也会被修改。
解决办法
首先这种现象并非一定是有问题的,有的应用场景就是希望保存对象的引用,但是这会导致部分误操作,如果不小心无意修改了对象的值就会导致数据不准确。
知道了原因那么也就好解决问题了:
使用immutable对象
将POJO设计成immutable的,如果需要修改就新建一个新的对象,这个也是fp所推崇的方案。
使用ehcache的copyStrategy
如果是遗留项目的话上面的方法可能就不适合了,好在在ehcache中已经实现了接口可以拦截read、write等操作,并对存入、读取的Element对象进行修改
public class MyCopyStrategy implements ReadWriteCopyStrategy<Element> {
//当write缓存的时候会调用这个方法
public Element copyForWrite(Element value, ClassLoader loader) {
Student temp=(Student) value.getObjectValue();
return new Element(value.getObjectKey(),new Student(temp.getName()+"_w"));
}
//当read缓存的时候会调用这个方法
public Element copyForRead(Element storedValue, ClassLoader loader) {
Student temp=(Student) storedValue.getObjectValue();
return new Element(storedValue.getObjectKey(),new Student(temp.getName()+"_r"));
}
}
如上只要实现了ReadWriteCopyStrategy就可以修改存入、读取的对象。这里在读取时我再名字后加了一个r,在存入时名字后加了一个w
还需要注入到cache中
//配置文件
<cache name="copyCache" maxEntriesLocalHeap="1" eternal="false"
timeToIdleSeconds="1" timeToLiveSeconds="1" copyOnRead="true" copyOnWrite="true">
<copyStrategy class="echach2.MyCopyStrategy" />
</cache>
使用copyStrategy将strategy配置到cache中,再运行上面的代码
张三_w_r
cache中取出的对象和源对象相等:false
两次cache中取出的对象相等false
这里可以看到存在的cache中的对象和原对象并不一样,两次cache取出来的对象也不同。
小结
ehcache的copyStratgy可以有效防止引用对象在外部被误改,但是这每次都复制一个对象,对性能还是有一定的影响的,所以可能的话还是尽量使用immutable的对象。
ehcache2拾遗之copyOnRead,copyOnWrite的更多相关文章
- ehcache2拾遗之write和load
问题描述 在cache系统中writeThrough和writeBehind是两个常用的模式. writeThrough是指,当用户更新缓存时,自动将值写入到数据源. writeBehind是指,在用 ...
- ehcache2拾遗之cache持久化
问题描述 应用在使用过程中会需要重启等,但是如果ehcache随着应用一起重启,那么刚重启的时候就会出现大量的miss,需要一定的访问量来重建缓存,如果缓存能够持久化,重启之后可以复用将会有助于缓解重 ...
- Ehcache(2.9.x) - API Developer Guide, Transaction Support
About Transaction Support Transactions are supported in versions of Ehcache 2.0 and higher. The 2.3. ...
- EhCache 配置信息
How to Size Caches 官方文档:http://ehcache.org/documentation/configuration/cache-size [maxEntriesLocalHe ...
- Terracotta
Terracotta 3.2.1简介 (一) 博客分类: 企业应用面临的问题 Java&Socket 开源组件的应用 hibernatejava集群服务器EhcacheQuartzTerrac ...
- Redis命令拾遗二(散列类型)
本文版权归博客园和作者吴双共同所有,欢迎转载,转载和爬虫请注明原文地址 :博客园蜗牛NoSql系列地址 http://www.cnblogs.com/tdws/tag/NoSql/ Redis命令拾 ...
- 基础拾遗------redis详解
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
- unixLike命令拾遗
针对在日常工作过程中,发现的学习的漏洞和忘记的知识,进行拾遗. 编辑命令 一.vim操作 1.进入编辑模式 在光标移到将要编辑处,点击i,进入编辑模式 2.退出编辑模式 按esc或者crtl+c退出编 ...
- 基础拾遗------webservice详解
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
随机推荐
- 也说说angularJs里的evalAsync
虽说angular都快出2.0了,到了2.0这些东东都会被干掉.不过我们眼前的事还是要处理. $evalAsync和$timeout到底什么区别,网上说法很多,最近看到的是说在directive里就怎 ...
- Keep It Simple Stupid!
Kelly Johnson提出了KISS原则.他是一个飞机工程师以及航空发明家,同时也是一个管理天才,他一生中主要设计了40多架飞机,获得的荣誉相当之多,总之,很牛. 这个原则是对Johnson带领的 ...
- the fourth class
6 居右 label加宽度,text-align:right 7 list copy: list1.concat(list1) 8 灵活运用addHandle,addEventListener 给in ...
- Android LayoutInflater原理分析,带你一步步深入了解View(一)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲Vi ...
- Caused by: java.lang.UnsatisfiedLinkError: Couldn't load BaiduMapVOS_v2_1_3: findLibrary returned nu
我是在整合百度LBS服务与百度语音识别服务的时候遇到这个问题的........ 解决办法是:不要导armeabi-v7a这个文件夹即可. 貌似还有的人试一下以下这种方法(这种方法来自:http://w ...
- Android应用程序Monkey测试
Monkey是Android SDK中附带的一个测试工具:Monkey用于进行压力测试,软件开发人员结合monkey打印日志和系统日志,解决测试中出现的问题. Monkey测试的特点:所有事件都是随机 ...
- Windows和linux的文件共享(1)
今天是我学习linux以来第一次写博客.带着一种激动心情我开始尝试着去完成第一篇博客.从易到难.所以第一次我就主要学习了Windows之间的文件共享. Window之间的文件共享是通过局域网实现的.局 ...
- [c语言]字符数组、字符串定义
C语言中字符串通常用字符指针和字符数组来定义: char* pS="abcdef"; char s[]="abcdef"; 这两种方式都会在结尾为字符串隐式补结 ...
- 《TCP/IP高效编程:改善网络程序的44个技巧》源码在Linux上的编译
为了先完整编译通过,需要以下几个步骤: 1.进入linux子目录,执行 make.(此步骤为打补丁.) 2.返回上一级目录,打开文件 simplec.c,添加头文件 #include <stdi ...
- java-代理模式及动态代理
代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在考虑到性能或安全等因素的情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. ...