ibatis 缓存 (cacheModel)详解

在Ibatis中使用Cache

java 2010-08-03 10:11:19 阅读53 评论0   字号: 订阅

文中的内容参考至IBATIS in action 的第九章Improving performance with caching。
入门样例
   首先是一个非常简单的Caching 实例
view plaincopy to clipboardprint?
<cacheModel id="categoryCache" type="MEMORY">   
   <flushOnExecute statement="insert"/>   
   <flushOnExecute statement="update"/>   
   <flushOnExecute statement="delete"/>   
   <property name="reference-type" value="WEAK"/>   
</cacheModel>   
<select   
   id="getCategory" parameterClass="Category"  
   resultClass="Category" cacheModel="categoryCache">   
   SELECT *   
   FROM Category   
   WHERE categoryId=#categoryId#   
</select>  
<cacheModel id="categoryCache" type="MEMORY">
   <flushOnExecute statement="insert"/>
   <flushOnExecute statement="update"/>
   <flushOnExecute statement="delete"/>
   <property name="reference-type" value="WEAK"/>
</cacheModel>
<select
   id="getCategory" parameterClass="Category"
   resultClass="Category" cacheModel="categoryCache">
   SELECT *
   FROM Category
   WHERE categoryId=#categoryId#
</select> 
   这个例子中有两个主要部件:Cache Model 和 映射语句(select),Cache Model定义了如何保存数据到Cache以及清除过时数据的清理策略。而映射语句(select或Procedure)想要使用Cache的时候只要对定义好的CacheModel加以引用。在这个例子中Cache Model的类型是MEMORY,这是Ibatis内建的cache方案。当flushOnExecute 元素中定义的方法被执行的时候,cache就会被flush掉。如果多个select使用了同一个Cache Model,这样几个select的cache结果都会被一起清除掉。cacheModel 的property元素用来为各个不同类型的缓存定义其特定的属性及其属性的value。
Ibatis的缓存方案跟传统O/R Mapping的缓存方案还是有所区别的。传统的OR Mapping会根据Ojbect的唯一标识符来缓存,这样当多次不同的结果返回相同结果的时候,对象只会被cache一次,而ibatis是直接对完全的结果进行缓存,而不管是否已经有相同的对象在cache中存在了。

CacheModel元素说明
   cacheModel元素包括了以下属性和子元素


Id(必选) 唯一的ID,让需要cache功能的select语句能够引用 
type(必选) cache的类型,合法的值包括MEMORY,LRU,FIFO,OSCACHE。如果需要自定义cache的类型就需要实现CacheController接口,type值的value就是实现类的类名 
readOnly(可选) 如果是true,表示这个cache是只读cache,从cache中获取对象的属性都不应该被修改。但设置成true并不能阻止对象属性被改变,如果对返回的结果做了改变,cache中的内容也会跟着改变。换句话说,readonly=true意味着应用程序要保证不会对cache的内容做任何改变。相反,readonly=false意味着应用程序会对返回结果加以修改,Ibais返回的缓存结果和ocache中的内容就不会使用同一个应用实例。该选项可选,缺省值是true 
serialize(可选) 这个属性意味着是否要在获取对象之前做“深度拷贝”。serialize=true意味着向缓存请求得到的内容都是cache对象深度拷贝的结果,即有相同的值但不是相同的实例。该选项可选,缺省值是false。 


readonly和serialize的组合会影响到应用程序的性能,

readonly serialize 结果 
true false 好 
false true 好 
false false 警告 
true true 差 


缓存类型
   MEMORY类型的cache只是简单的将cache的数据放入到内存中,只到GC将其释放。Memory类型的cache只有一个属性reference-type,其值可以是WEAK、SOFT、Strong三种类型的引用。使用WEAK、SOFT这两种引用,GC会根据内存的使用情况和缓存内容的访问状况来决定缓存内容的清除还是保留。而使用Strong引用缓存起来的内容会一直保留下来只到被Flush掉。下面是该类型缓存使用样例。
view plaincopy to clipboardprint?
<cacheModel id="categoryCache" type="MEMORY">  
   <flushInterval hours="24"/>  
   <flushOnExecute statement="insert"/>  
   <flushOnExecute statement="update"/>  
   <flushOnExecute statement="delete"/>  
   <property name="reference-type" value="WEAK"/>  
</cacheModel>   
<cacheModel id="categoryCache" type="MEMORY">
   <flushInterval hours="24"/>
   <flushOnExecute statement="insert"/>
   <flushOnExecute statement="update"/>
   <flushOnExecute statement="delete"/>
   <property name="reference-type" value="WEAK"/>
</cacheModel> 

   LRU类型的cache有一个最大缓存数,当保存的数量超过这个值的时候,Ibatis会依据“least recently used”的算法将数据从缓存中清除。LRU类型的缓存惟一可以设置的属性就是这个最大缓存数。下面是该类型缓存使用样例。
view plaincopy to clipboardprint?
<cacheModel id="categoryCache" type="LRU">  
   <flushInterval hours="24"/>  
   <flushOnExecute statement="insert"/>  
   <flushOnExecute statement="update"/>  
   <flushOnExecute statement="delete"/>  
   <property name="size" value="200"/>  
</cacheModel>  
<cacheModel id="categoryCache" type="LRU">
   <flushInterval hours="24"/>
   <flushOnExecute statement="insert"/>
   <flushOnExecute statement="update"/>
   <flushOnExecute statement="delete"/>
   <property name="size" value="200"/>
</cacheModel> 

   FIFO类型cache跟LRU类型的缓存类似也有一个固定的SIZE,不同的是其使用使用的是“先进先出”的策略。该类型的缓存惟一可以设置的属性就是这个最大缓存数。下面是该类型缓存使用样例。
view plaincopy to clipboardprint?
<cacheModel id="categoryCache" type="FIFO">  
   <flushInterval hours="24"/>  
   <flushOnExecute statement="insert"/>  
   <flushOnExecute statement="update"/>  
   <flushOnExecute statement="delete"/>  
   <property name="size" value="1000"/>  
</cacheModel>  
<cacheModel id="categoryCache" type="FIFO">
   <flushInterval hours="24"/>
   <flushOnExecute statement="insert"/>
   <flushOnExecute statement="update"/>
   <flushOnExecute statement="delete"/>
   <property name="size" value="1000"/>
</cacheModel> 

   OSCACHE类型的cache值得就是使用OpenSymphony的oscache作为cache的实现方案。
   当然我们还可以通过实现CacheController接口来使用我们自己的缓存方案。
Cache的清除
Ibatis定义了两中tag——flushOnExecute和flushInterval来处理cache内容的清除。flushOnExecute的statement属性用来引用那些会引起缓存清除的语句。下面是一个flushOnExecute的使用案例
view plaincopy to clipboardprint?
<sqlMap namespace="Category">  
…   
<cacheModel id="categoryCache" type="MEMORY">  
…   
<flushOnExecute statement="Category.insert"/>  
…   
</cacheModel>  
…   
<select  
id="getCategory" parameterClass="Category"  
resultClass="Category" cacheModel="categoryCache">  
SELECT *   
FROM Category   
WHERE parentCategoryId=#categoryId#   
</select>  
…   
<insert id="insert" parameterClass="Category" >  
INSERT INTO Category   
(title,description,sequence)   
VALUES   
(#title#,#description#,#sequence#)   
</insert>  
…   
</sqlMap>  
<sqlMap namespace="Category">
<cacheModel id="categoryCache" type="MEMORY">
<flushOnExecute statement="Category.insert"/>
</cacheModel>
<select
id="getCategory" parameterClass="Category"
resultClass="Category" cacheModel="categoryCache">
SELECT *
FROM Category
WHERE parentCategoryId=#categoryId#
</select>
<insert id="insert" parameterClass="Category" >
INSERT INTO Category
(title,description,sequence)
VALUES
(#title#,#description#,#sequence#)
</insert>
</sqlMap> 

   需要注意的是如果statement对应的sqlmap使用了namespace,statement就要填写完整的语句名称,即便statement引用的映射语句就在同个namespace中,如果statement引用的映射语句在其他的sqlmap配置文件中,那就要保证引用的语句
flushInterval则是用来定义连续的、定时的、重复的缓存清除。flushInterval有四个属性hours、minutes、second、millisecondss,例如以下这个例子
view plaincopy to clipboardprint?
<cacheModel id="categoryCache" type="MEMORY">  
…   
<flushInterval hours= "12" />  
…   
</cacheModel>  
<cacheModel id="categoryCache" type="MEMORY">
<flushInterval hours= "12" />
</cacheModel> 
总结
   Ibatis内建了对Cache的支持,目的就是通过cache的运用来提升性能和Scalability等等。但跟App自己使用Cache一样,Ibatis对cache的使用同样要考虑集群、其他应用直接修改数据库等问题。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dearhwj/archive/2009/04/03/4005314.aspx

一下内容来自iBatis开发指南



--------------------------------------------------------------------------------


Cache 
在特定硬件基础上(同时假设系统不存在设计上的缺漏和糟糕低效的SQL 语句) 
Cache 往往是提升系统性能的最关键因素)。
相对Hibernate 等封装较为严密的ORM 实现而言(因为对数据对象的操作实现
了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭
的封装实现,因此对缓存的操作难以做到完全的自动化同步)。
ibatis 的缓存机制使用必须特别谨慎。特别是flushOnExecute 的设定(见
“ibatis 配置”一节中的相关内容),需要考虑到所有可能引起实际数据与缓存数据
不符的操作。如本模块中其他Statement 对数据的更新,其他模块对数据的更新,甚
至第三方系统对数据的更新。否则,脏数据的出现将为系统的正常运行造成极大隐患。
如果不能完全确定数据更新操作的波及范围,建议避免Cache 的盲目使用。
结合cacheModel 来看: 
<cacheModel
id="product-cache"
type ="LRU"
readOnly="true"
serialize="false">
</cacheModel>
可以看到,Cache 有如下几个比较重要的属性: 
. readOnly 
. serialize 
. type 
readOnly 
readOnly 值的是缓存中的数据对象是否只读。这里的只读并不是意味着数据对象一
旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对
象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要重新从数据
库读取数据,构造新的数据对象。
而readOnly="false" 则意味着缓存中的数据对象可更新,如user 对象的name 
属性发生改变。
只读Cache 能提供更高的读取性能,但一旦数据发生改变,则效率降低。系统设计
时需根据系统的实际情况(数据发生更新的概率有多大)来决定Cache 的读写策略。

serialize 
如果需要全局的数据缓存,CacheModel 的serialize 属性必须被设为true 。否则数据
缓存只对当前Session(可简单理解为当前线程)有效,局部缓存对系统的整体性能提
升有限。
在serialize="true" 的情况下,如果有多个Session 同时从Cache 中读取某个
数据对象,Cache 将为每个Session 返回一个对象的复本,也就是说,每个Session 将
得到包含相同信息的不同对象实例。因而Session 可以对其从Cache 获得的数据进行
存取而无需担心多线程并发情况下的同步冲突。
Cache Type: 
与hibernate 类似,ibatis 通过缓冲接口的插件式实现,提供了多种Cache 的实现机
制可供选择: 
1. MEMORY 
2. LRU 
3. FIFO 
4. OSCACHE 
MEMORY 类型Cache 与WeakReference 
MEMORY 类型的Cache 实现,实际上是通过Java 对象引用进行。ibatis 中,其实现类
为com.ibatis.db.sqlmap.cache.memory.MemoryCacheController,MemoryCacheController 内部,
使用一个HashMap 来保存当前需要缓存的数据对象的引用。
这里需要注意的是Java2 中的三种对象引用关系: 
a SoftReference 
b WeakReference 
c PhantomReference 
传统的Java 对象引用, 如:
public void doSomeThing(){ 
User user = new User() 
……
当doSomeThing 方法结束时,user 对象的引用丢失,其所占的内存空间将由JVM 在下
次垃圾回收时收回。如果我们将user 对象的引用保存在一个全局的HashMap 中,如:
Map map = new HashMap(); 
public void doSomeThing(){ 
User user = new User(); 
map.put("user",user); 
此时,user 对象由于在map 中保存了引用,只要这个引用存在,那么JVM 永远也不会
收回user 对象所占用的内存。
这样的内存管理机制相信诸位都已经耳熟能详,在绝大多数情况下,这几乎是一种完美

的解决方案。但在某些情况下,却有些不便。如对于这里的Cache 而言,当user 对象使用
之后,我们希望保留其引用以供下次需要的时候可以重复使用,但又不希望这个引用长期保
存, 如果每个对象的引用都长期保存下去的话,那随着时间推移,有限的内存空间将立即被
这些数据所消耗殆尽。最好的方式,莫过于有一种引用方式,可以在对象没有被垃圾回收器
回收之前,依然能够访问此对象,当垃圾回收器启动时,如果此对象没有被其他对象所使用,
则按照常规对其进行回收。
SoftReference 、WeakReference 、PhantomReference 为上面的思路提供了有力支持。
这三种类型的引用都属于“非持续性引用”,也就是说,这种引用关系并非持续存在,
它们所代表的引用的生命周期与JVM 的运行密切相关,而非与传统意义上的引用一样依赖
于编码阶段的预先规划。
先看一个SoftReference 的例子: 
SoftReference ref; 
public void doSomeThing(){ 
User user = new User(); 
ref = new SoftReference(user); 
public void doAnotherThing(){ 
User user = (User)ref.get();//通过SoftReference 获得对象引用
System.out.println(user.getName()); 
假设我们先执行了doSomeThing 方法,产生了一个User 对象,并为其创建了一个
SoftReference 引用。
之后的某个时刻,我们调用了doAnotherThing 方法,并通过SoftReference 获取User 对
象的引用。
此时我们是否还能取得user 对象的引用?这要看JVM 的运行情况。对于SoftReference 
而言,只有当目前内存不足的情况下,JVM 在垃圾回收时才会收回其包含的引用(JVM 并
不是只有当内存不足时才启动垃圾回收机制, 何时进行垃圾回收取决于各版本JVM 的垃圾
回收策略。如某这垃圾回收策略为:当系统目前较为空闲, 且无效对象达到一定比率时启动
垃圾回收机制,此时的空余内存倒可能还比较充裕)。这里可能出现两种情况,即: 
. JVM 目前还未出现过因内存不足所引起的垃圾回收,user 对象的引用可以通过
SoftReference 从JVM Heap 中收回。
. JVM 已经因为内存不足启动了垃圾回收机制,SoftReference 所包含的user 对象的
引用被JVM 所废弃。此时ref.get 方法将返回一个空引用(null),对于上面
的代码而言,也就意味着这里可能抛出一个NullPointerException 。
WeakReference 比SoftReference 在引用的维持性上来看更加微弱。无需等到内存不足的
情况,只要JVM 启动了垃圾回收机制,那么WeakReference 所对应的对象就将被JVM 回收。

也就是说,相对SoftReference 而言,WeakReference 被JVM 回收的概率更大。
PhantomReference 比WeakReference 的引用维持性更弱。与WeakReference 和
SoftReference 不同,PhantomReference 所引用的对象几乎无法被回收重用。它指向的对象实
际上已经被JVM 销毁(finalize 方法已经被执行),只是暂时还没被垃圾回收器收回而已。
PhantomReference 主要用于辅助对象的销毁过程,在实际应用层研发中,几乎不会涉及。
MEMORY 类型的Cache 正是借助SoftReference 、WeakReference 以及通常意义上的Java 
Reference 实现了对象的缓存管理。
下面是一个典型的MEMORY 类型Cache 配置: 
<cacheModel id="user_cache" type="MEMORY"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="reference-type" value="WEAK" /> 
</cacheModel> 
其中flushInterval 指定了多长时间清除缓存,上例中指定每24 小时强行清空缓存
区的所有内容。
reference-type 属性可以有以下几种配置: 
1. STRONG 
即基于传统的Java 对象引用机制,除非对Cache 显式清空(如到了flushInterval 
设定的时间;执行了flushOnExecute 所指定的方法;或代码中对Cache 执行了清除
操作等),否则引用将被持续保留。
此类型的设定适用于缓存常用的数据对象, 或者当前系统内存非常充裕的情况。
2. SOFT 
基于SoftReference 的缓存实现,只有JVM 内存不足的时候,才会对缓冲池中的数
据对象进行回收。
此类型的设定适用于系统内存较为充裕,且系统并发量比较稳定的情况。
3. WEAK 
基于WeakReference 的缓存实现,当JVM 垃圾回收时,缓存中的数据对象将被JVM 
收回。
一般情况下,可以采用WEAK 的MEMORY 型Cache 配置。
LRU 型Cache 
当Cache 达到预先设定的最大容量时,ibatis 会按照“最少使用”原则将使用频率最少
的对象从缓冲中清除。
<cacheModel id="userCache" type="LRU"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
可配置的参数有:
. flushInterval 
指定了多长时间清除缓存,上例中指定每24小时强行清空缓存区的所有内容。
. size 

Cache 的最大容量。
FIFO 型Cache 
先进先出型缓存,最先放入Cache 中的数据将被最先废除。可配置参数与LRU 型相同: 
<cacheModel id="userCache" type="FIFO"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
OSCache 
与上面几种类型的Cache 不同,OSCache 来自第三方组织Opensymphony 。可以通过以
下网址获得OSCache 的最新版本(http://www.opensymphony.com/oscache/)。
在生产部署时,建议采用OSCache,OSCache 是得到了广泛使用的开源Cache 实现
(Hibernate 中也提供了对OSCache 的支持),它基于更加可靠高效的设计,更重要的是,
最新版本的OSCache 已经支持Cache 集群。如果系统需要部署在集群中,或者需要部署在
多机负载均衡模式的环境中以获得性能上的优势,那么OSCache 在这里则是不二之选。
Ibatis 中对于OSCache 的配置相当简单: 
<cacheModel id="userCache" type="OSCACHE"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
之所以配置简单,原因在于,OSCache 拥有自己的配置文件(oscache.properties)J。
下面是一个典型的OSCache 配置文件:
#是否使用内存作为缓存空间
cache.memory=true 
#缓存管理事件监听器,通过这个监听器可以获知当前Cache 的运行情况
cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JMSBroa 
dcastingListener 
#如果使用磁盘缓存(cache.memory=false),则需要指定磁盘存储接口实现
#cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.Disk 
PersistenceListener 
# 磁盘缓存所使用的文件存储路径
# cache.path=c:\\myapp\\cache 
# 缓存调度算法,可选的有LRU,FIFO 和无限缓存(UnlimitedCache) 

# cache.algorithm=com.opensymphony.oscache.base.algorithm.FIFOCache 
# cache.algorithm=com.opensymphony.oscache.base.algorithm.UnlimitedCache 
cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache 
#内存缓存的最大容量
cache.capacity=1000 
# 是否限制磁盘缓存的容量
# cache.unlimited.disk=false 
# 基于JMS 的集群缓存同步配置
#cache.cluster.jms.topic.factory=java:comp/env/jms/TopicConnectionFactory 
#cache.cluster.jms.topic.name=java:comp/env/jms/OSCacheTopic 
#cache.cluster.jms.node.name=node1 
# 基于JAVAGROUP 的集群缓存同步配置
#cache.cluster.properties=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ 
ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout 
=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000 
):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransm 
it_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000): 
UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=fal 
se):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_loc 
al_addr=true) 
#cache.cluster.multicast.ip=231.12.21.132 
配置好之后,将此文件放在CLASSPATH 中,OSCache 在初始化时会自动找到此
文件并根据其中的配置创建缓存实例。

 

 

 

 

 

 

 

 

 

 

iBATIS CacheModel使用浅析

iBATIS CacheModel的使用是什么情况呢?让我们首先从现状入手,Cache也是经常讨论的一个话题之一,在我们系统开发的过程中,总会存在着这样一类数据,它们更新频率很低,然而使用的频率却非常之高。为了提高系统性能,我们通常将此类数据装入缓存。iBATIS.NET也有自己的缓存系统。

MappedStatement的查询结果集可以根据CacheModel的值来确定它是否被装入缓存以及如何装入缓存。而iBATIS CacheModel也是在配置文件中事先定义好的。具体的定义方式如下:

  1. ﹤cacheModel id="employee-cache" implementation="LRU" readOnly="true" serialize="false"﹥  
  2.   ﹤flushInterval hours="24"/﹥  
  3.   ﹤flushOnExecute  statement="insertEmployee"/﹥  
  4.   ﹤flushOnExecute  statement="updateEmployee"/﹥  
  5.   ﹤flushOnExecute  statement="deleteEmployee"/﹥  
  6.   ﹤property name="CacheSize" value="100"/﹥  
  7. ﹤/cacheModel﹥ 

iBATIS CacheModel使用浅析配置好之后,它会创建一个名为"employee-cache"的缓存实例,implementation表示它的实现规则是LRU,即:Leaste Recently Used。iBATIS.NET还有MEMORY,FIFO几种缓存的模式。

readOnly的值说明缓存是只读的还是可读写的,如果readOnly为true,缓存就是只读,false为可读写。

serialize指示缓存是在整个Application中有效还是仅作用于当前的Session。flushInterval的值表示缓存的有效期,上面的配置中则表示改缓存每24小时清空一次,当然有效期还可以用minutes, seconds or milliseconds来表示。

flushOnExecute表示缓存将在执行了什么操作时被清空,上面的配置中表示该缓存在执行insertEmployee or updateEmployee or deleteEmployee时被清空。

CacheSize表示缓存的最大条目,当超过这个值的时候就会按照implementation中定义的规则来清除相应的条目,上面配置中则表示当缓存的条目超过100时,则移出最近最少使用的条目。当我们配置好cacheModel之后就可以在statement中使用了,如下:

  1. ﹤statement id="EmployeeList" cacheModel="employee-cache"﹥  
  2.   select * from Employee  
  3. ﹤/statement﹥ 
 

iBATIS CacheModel的相关情况就介绍到这里,希望对你了解iBATIS CacheModel缓存系统有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值