- 浏览: 922235 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (251)
- WebService (17)
- IBatis (22)
- Hibernate (1)
- SpringMVC - 基础篇 (32)
- Spring (15)
- Java (11)
- JVM及调优 - 基础篇 (4)
- 集群 (14)
- 数据库 (17)
- WebSphere (5)
- 多线程 (4)
- 集合、容器 (2)
- DB Pool (1)
- Power Designer (5)
- Maven基础 (5)
- JS (14)
- WEB 前端 (5)
- 实用小工具 (17)
- 社会、人 (2)
- 乱七八糟 (18)
- ASM&CGLIB - 基础篇 (12)
- 缓存 (1)
- 性能 (1)
- 设计之殇 (1)
- 分布式事务 (1)
- 单点登录 (11)
- 分布式 Session (4)
- Memcached - 基础篇 (6)
最新评论
-
一笑_奈何:
楼主写的还真行不错。
扫盲贴 - J2EE集群之JNDI集群实现 -
xuezhongyu01:
博主写的很详细,但最后还是没明白,最后调用BasicDataS ...
Spring中的destroy-method方法 -
Mr梁:
commons-fileupload.jar commons- ...
SpringMVC 中文件上传 MultipartResolver -
Eywa:
总结的很不错
ORACLE CASE WHEN 及 SELECT CASE WHEN的用法 -
TryRelax:
fastjson 比 jackson 好用吧?
Spring MVC Jackson DateFormat
为了提高应用程序性能,一种比较通用的方法是使用缓存技术来减少与数据库之间的交互。缓存技术是一种“以空间换时间”的设计理念,利用内存空间资源来提高数据检索速度的有效手段之一。
iBATIS以一种简单、易用、灵活的方式实现了数据缓存。下面,首先看一下iBATIS关于缓存部分的核心类图:
关于这些类的用途,在注释中做了比较概括性的说明,下面就来仔细的讲一下这些类的用途以及它们是如何工作的。
在iBATIS中,可以配置多个缓存,每个cacheModel的配置对应一个CacheModel类的一个对象。其中包括id等配置信息。iBATIS通过这些配置信息来定义缓存管理的行为。
缓存的目的是为了能够实现数据的高速检索。在程序中,数据是用对象表示的;为了能够检索到以缓存的数据对象,每个数据对象必须拥有一个唯一标识,在iBATIS中,这个唯一标识用CacheKey来表示。
那么,缓存的数据保存到什么地方了呢?如何实现数据的快速检索呢?答案在CacheController的实现类中。每个CacheController中都有一个Map类型的属性cache来保存被缓存的数据,其中key为CacheKey类型,value为Object类型;需要关注的是CacheKey对象的hashCode的生成算法,每次调用CacheKey对象的update方法时,都会更新它的hashCode值,关于hashCode值的计算方法后续在给出详细说明。
在拥有了数据缓存区后,就可以向其中存放数据和检索数据了。在iBATIS中,有多种的缓存管理策略,也可以自定义缓存管理策略。
关于缓存的功能,主要有两种类型:一种是对外提供的功能:数据存储和数据检索;另外一种是内部管理的功能:缓存对象标识的生成,缓存区刷新,数据检索算法等。下面就逐一介绍这些功能的代码实现。
1. 数据存储
首先看一下CacheModel中的putObject方法是如何实现的
public void putObject(CacheKey key, Object value) {
if (null == value) value = NULL_OBJECT; //关于缓存的操作,需要互斥 synchronized ( this ) { if (serialize && !readOnly && value != NULL_OBJECT) { //需要序列化,并且非只读,则需要将缓存对象序列化到内存,以供后续检索使用 //readOnly为false时,不能直接将对象引用直接返回个客户程序 try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(value); oos.flush(); oos.close(); value = bos.toByteArray(); } catch (IOException e) { throw new RuntimeException("Error caching serializable object. Cause: " + e, e); } } //如果执行了内存序列化,则保存的是它的字节数组 controller.putObject(this, key, value); if ( log.isDebugEnabled() ) { log("stored object", true, value); } } }
因为真正缓存数据对象的地方是在CacheController中,所以CacheModel的putObject方法中会调用CacheController的putObject方法执行真正的数据存储。由于不同的CacheController实现的缓存管理方式不同,所以putObject实现也各不相同。下面分别介绍不同的CacheController实现的putObject方法
1) FifoCacheController
public void putObject(CacheModel cacheModel, Object key, Object value) {
//保存到Map中 cache.put(key, value); //保存key到keyList keyList.add(key); //如果当前key的数量大于缓存容量时,移除keyList和cache中的第一个元素,达到先进先出的目的 if (keyList.size() > cacheSize) { try { Object oldestKey = keyList.remove(0); cache.remove(oldestKey); } catch (IndexOutOfBoundsException e) { //ignore } } }
2)LruCacheController
public void putObject(CacheModel cacheModel, Object key, Object value) { cache.put(key, value); keyList.add(key); if (keyList.size() > cacheSize) { try { //取得keyList中的第一个元素作为最近最少用的key,为什么呢? //这个问题等到讲解它的getObject方法时别会知晓 Object oldestKey = keyList.remove(0); cache.remove(oldestKey); } catch (IndexOutOfBoundsException e) { //ignore } } }
3)MemoryCacheController
public void putObject(CacheModel cacheModel, Object key, Object value) { Object reference = null; //根据配置创建响应的引用类型,此种缓存管理方式完全交给jvm的垃圾回收器来管理 //创建好引用后,将数据对象放入到引用中 if (referenceType.equals(MemoryCacheLevel.WEAK)) { reference = new WeakReference(value); } else if (referenceType.equals(MemoryCacheLevel.SOFT)) { reference = new SoftReference(value); } else if (referenceType.equals(MemoryCacheLevel.STRONG)) { reference = new StrongReference(value); } //在缓存中保存引用 cache.put(key, reference); }4)OSCacheController
这个缓存管理使用了OSCache来管理缓存,这里就不做仔细的介绍了。
2. 数据检索
在数据被放置到缓存区中以后,程序需要根据一定的条件进行数据检索。首先看一下CacheModel类的getObject方法是如何检索数据的
public Object getObject(CacheKey key) { Object value = null; //互斥访问缓冲区 synchronized (this) { if (flushInterval != NO_FLUSH_INTERVAL && System.currentTimeMillis() - lastFlush > flushInterval) { //如果到了定期刷新缓冲区时,则执行刷新 flush(); } //根据key来从CacheController中取得数据对象 value = controller.getObject(this, key); if (serialize && !readOnly && (value != NULL_OBJECT && value != null)) { //如果需要序列化,并且非只读,则从内存中序列化出一个数据对象的副本 try { ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value); ObjectInputStream ois = new ObjectInputStream(bis); value = ois.readObject(); ois.close(); } catch (Exception e) { throw new RuntimeException("Error caching serializable object. Be sure you're not attempting to use " + "a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e); } } //下面的两个操作是用来计算缓存区数据检索的命中率的 //对于缓冲区的数据检索请求加一操作 requests++; //如果检索到数据,则命中数加一 if (value != null) { hits++; } if ( log.isDebugEnabled() ) { if ( value != null ) { log("retrieved object", true, value); } else { log("cache miss", false, null); } } } return value; }真正的数据检索操作是在CacheController的实现类中进行的,下面就分别来看一下各个实现类是如何检索数据的。
1) FifoCacheController
public Object getObject(CacheModel cacheModel, Object key) { //直接从Map中取得 return cache.get(key); }
2) LruCacheController
public Object getObject(CacheModel cacheModel, Object key) { Object result = cache.get(key); //因为这个key被使用了,如果检索到了数据,则将其移除并重新放置到队尾 //这样的目的就是保持最近使用的key放在队尾,而对头为最近未使用的 //如果没有检索到对象,则直接将该key移除 keyList.remove(key); if (result != null) { keyList.add(key); } return result; }
3) MemoryCacheController
public Object getObject(CacheModel cacheModel, Object key) { Object value = null; //取得引用对象 Object ref = cache.get(key); if (ref != null) { //从引用对象中取得数据对象 if (ref instanceof StrongReference) { value = ((StrongReference) ref).get(); } else if (ref instanceof SoftReference) { value = ((SoftReference) ref).get(); } else if (ref instanceof WeakReference) { value = ((WeakReference) ref).get(); } } return value; }
3 唯一标识的生成
在iBATIS中,用CacheKey来标识一个缓存对象,而CacheKey通常是作为Map中的key存在,所以CacheKey的hashCode的计算方法异常重要。影响hashCode的值有很多方面的因素,对每一个影响hashCode的元素,都需要调用CacheKey的update方法来重新计算hashCode值。下面我们就来看一下CacheKey的创建以及计算的相关过程。
首先CacheKey是在BaseDataExchange类的getCacheKey方法中被创建的。
public CacheKey getCacheKey(StatementScope statementScope, ParameterMap parameterMap, Object parameterObject) { CacheKey key = new CacheKey(); //取得parameterObject中的数据,这个parameterObject就是客户端传递过来的参数对象 Object[] data = getData(statementScope, parameterMap, parameterObject); //根据parameterObject中的数据去重计算hashCode for (int i = 0; i < data.length; i++) { if (data[i] != null) { key.update(data[i]); } } return key; }
这个方法被MappedStatement中的getCacheKey调用
public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) { Sql sql = statementScope.getSql(); ParameterMap pmap = sql.getParameterMap(statementScope, parameterObject); CacheKey cacheKey = pmap.getCacheKey(statementScope, parameterObject); //statement id对hashCode有影响 cacheKey.update(id); cacheKey.update(baseCacheKey); //sql语句对hashCode有影响 cacheKey.update(sql.getSql(statementScope, parameterObject)); //Fixes bug 953001 return cacheKey; }
真正需要CacheKey对象的地方是在CacheStatement类中
public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) { CacheKey key = statement.getCacheKey(statementScope, parameterObject); //如果不可读并且不被序列化,那么当前的SessionScope也对hashCode有影响 //而真正起作用的是SessionScope的id属性 //也就是说这个缓存与调用线程的会话有关,当前线程所存储的数据不能被其他线程使用 if (!cacheModel.isReadOnly() && !cacheModel.isSerialize()) { key.update(statementScope.getSession()); } return key; }
经过上述一系列的getCacheKey调用,将对CacheKey有影响的因素施加给了hashCode。其中对CacheKey的hashCode起影响作用的因素主要有:baseCacheKey,sql语句,参数值,statement id。可能产生影响的因素是session id。
现在我们知道了决定CacheKey的相关因素,也就知道了iBATIS是如何唯一的确定一个缓存对象。
经过以上的代码分析,可以掌握iBatis如何生成CacheKey对象和计算其hashCode值,以及存储和检索数据对象。这些正是iBATIS缓存的基础,掌握了这些实现原理,有助于我们更高效的使用iBATIS缓存功能,或者是开发自己的缓存系统。
===========原文:http://blog.csdn.net/prince2270/article/details/5977512======
具体配置参考:
http://exceptioneye.iteye.com/blog/1054351和http://exceptioneye.iteye.com/blog/1054355
发表评论
-
iBatis批处理(batch)
2011-09-05 23:47 6838spring集成了ibatis的批量提交的功能,我们只要调用A ... -
一个Spring+iBatis框架进行batch处理的问题
2011-09-05 23:23 1591在使用org.springframework.jdbc.dat ... -
ibatis 注意点
2011-08-08 19:28 1341insert,update,delete 返回值 inser ... -
ibatis 之 动态SQL查询(dynamic )
2011-06-12 12:13 2255映射文件: <select id=" ... -
ibatis 之 复杂类型集合的属性
2011-06-12 12:10 2116Result Map还可以装入代表复杂类型对象集合(List) ... -
ibatis 之 复杂类型属性(即自定义类型的属性)
2011-06-12 11:54 3422复杂类型用以表示在数 ... -
ibatis 之 java.util.Map作为parameterClass和resultClass
2011-06-12 11:21 51271.Map作为parameterClass 映射 ... -
ibatis Tips 之 resultMap
2011-05-29 21:04 1158转载:http://xulongfa.iteye.com/bl ... -
ibatis Tips之parameterMap
2011-05-29 21:03 1314转载:http://xulongfa.iteye.com/bl ... -
iBatis查询API
2011-05-29 12:34 1826转载:http://sarin.iteye.com/blog/ ... -
iBatis查询select详解
2011-05-29 12:20 2190转载:http://sarin.iteye.com/blog/ ... -
ibatis 表与表的关联查询
2011-05-22 15:04 1240ibatis高级特性,处理表与表之间的关联。ibatis中,提 ... -
ibatis 动态映射机制
2011-05-22 14:15 1424对于这个组合查询页 ... -
sqlMapConfig.xml配置文件详解
2011-05-22 13:04 3524sqlMapConfig.xml配置文件详解: X ... -
ibatis缓存
2011-05-22 12:52 1327iBatis的缓存配置比较简单易懂,以我使用的iBati ... -
ibatis resultclass "java.util.hashmap" 缓存问题
2011-05-22 12:13 1488在做ibatis项目过程中遇到如下样式动态查询 <se ... -
ibatis # $区别
2011-05-22 11:55 14091、#可以进行预编译,进行类型匹配,#变量名# 会转化为 j ... -
iBATIS入门示例及注释
2011-05-08 18:20 1723工程的结构: 一、SqlMapConf ... -
iBATIS 三个版本小细节对比
2011-05-08 16:12 1178iBATIS 三个版本小细节对比 sqlMapConfig ... -
深入分析 iBATIS 框架之系统架构与映射原理
2011-05-07 12:48 1188原文:http://www.ibm.com/developer ...
相关推荐
iBATIS缓存介绍 iBATIS二级缓存 iBATIS缓存配置
ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园
iBATIS缓存的使用方法
ibatis 缓存配置策略,学习篇 • iBatis对查询结果集进行本地缓存。 • Cache的key由haskcode、checksum、查询参数、sqlmap Id、sql语句、调用方法名等构成。由此可以看出,不同的参数会有不同的Key。注意,他不是以...
如何解决动态数据表名,动态字段名情况下,由ibatis缓存select字段而引起的字段找不到的情况?以下是最简单的解决办法! 本文中内容真实可靠,保证用户很快掌握
Java ibatis缓存技术,ibatis缓存的详细解释 值得学习!
ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网
Java_ibatis缓存技术
iBATIS缓存介绍[借鉴].pdf
ibatis 数据缓存,帮你了解ibatis的数据缓存机制。
ibatis 数据缓存,讨论了ibatis 数据缓存方面的概念,即用法,用到ibatis 数据缓存的可以参考一下
NULL 博文链接:https://sunfish.iteye.com/blog/1493410
缓存不算是ibatis框架的一个亮点,但理解ibatis的缓存设计和实现对我们合理使用ibatis缓存是很有帮助的。
高性能是J2EE应用程序追求的目标,在特定硬件基础上,数据...在对 iBATIS的缓存支持情况进行了介绍和研究的基础上,并结合Spring框架和iBATIS,使用Memcached对iBATIS二级缓存进行了新的实现,使应用的性能得到了很大的提升.
ibatis缓存技术详解,详细讲述了ibaits缓存应用于实现。
Oscache.jar包 博文链接:https://dangzhao.iteye.com/blog/193572
spring+ibatis+oracle分页缓存源码