(一)背景
简而言之一句话,减少服务器处理次数,加快访问速度。
(二)ibatis缓存的使用方法
在要使用的xml模块中添加cacheModel模块,例如:
<cacheModel id="user-cache" type="LRU" readOnly="false"
serialize="true">
<flushInterval hours="24" />
<flushOnExecute statement="getUser" />
<property value="600" name="size" />
</cacheModel>
id : 缓存模块cacheModel唯一性的标志。
type: 缓存的类型。目前使用的缓存类型有四种:
FIFO:com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController
LRU:com.ibatis.sqlmap.engine.cache.fifo.LruCacheController
MEMORY:com.ibatis.sqlmap.engine.cache.fifo.MemoryCacheController
OSCACHE:com.ibatis.sqlmap.engine.cache.fifo.OSCacheController
当然,你也可以自己来实现Cache, 你需要做的是让你的Cache类 implements com.ibatis.sqlmap.engine.cache.CacheController.
readOnly:是否只读. 默认为true, 只读。
Serialize:是否从Cache中读取同一个对象,还是对象的副本。只有在readOnly=false才有效.
因为Cache是只读的,那么为不同session返回的对象肯定是一个.
只有在Cache是可读写的时候,才需要为每个session返回对象的副本.
这种缓存为每一个Session返回缓存对象不同的实例(复本)。因此每一个Session都可以安全修改返回的对象. 注意,此时readOnly必须为false。如果你把它设为 true ,记得检查两件事,一件事是缓存中存放的对象(你想查询的POJO)必须是可序列化的,即实现Serializable接口。如果你有一个复杂对象属性,它也必须满足这个规则,你的整个对象树必须是可序列化的。另一件事是关闭sql-map-config中的延迟加载属性,即lazyload=false,原因是,它使用了动态代理机制,那个代理对象并不是Serializable的。
flushInterval:Cache刷新间隔. 可以配置hours,minutes,seconds,milliseconds.
注:不是说间隔时间到了,在cache的statement会自己刷新,而是说,见间隔时间过了后,在下次的查询的时候,江不会是直接去cache中拿值,而会用sql去取值,也就是: 如果,间隔时间过了,还没有Cache对应的statement执行的话,那么Cache中就会一直是旧的,不用担心Cache数据是旧的,因为下次的查询将会直接从SQL查询,而非Cache,查询的结果也会去更新Cache的值。
一个 cacheModel 只能有一个 flushInteval 元素
flushOnExecute :当这些statement被执行了,那么下次的查询将会通过SQL去查,同时用查询结果更新Cache.
注: 和flushInterval的刷新一样,不是主动刷新,而是由下次查询来触发被动刷新。
在一个cacheModel中可以指定多个flushOnExecute。
statement:就是需要被执行的statement的id
cacheModel可以定义任意多的flushOnExecute元素
property:这是针对cacheModel的额外的一些属性配置.不同type的cacheModel将会有自己专有的一些property配置.
在 LRU cache model 中,cache-size指定了缓存储存的项数
FIFO: <property name="size" value="100" />
LRU: <property name="cache-size" value="100" />
MEMORY: <property name="reference-type" value="WEAK" />
(四)使用示例
在statment的使用上,直接加一个cacheModel属性指向id即可。
<select id="getAllUser" resultClass="user" cacheModel="user-cache">
select * from user;
</select>
(五)注意事项
1)MEMORY 没有统一的对象重用模式的应用,或内存不足的应用。
WEAK是默认,大多数情况下是最好的选择,能大大提高查用查询的性能,但对于当前不被使用的查询结果数据,将被清除以释放内存来分配其他对象。
LRU 实现用近期最少使用的原则来确定如何从Cache中清除对象。对于较长的时间内,一些用户经常使用某些特定对象的情况(例如,在PaginatedList和常用的查询关键字结果集中翻页),LRU Cache是不错的选择。
size必须为整数,代表保存在Cache的中对象的最大数目。因此不要Cache太多的对象,以免内存不足。
FIFO 实现用先进先出的原则来确定如何从Cache中清除对象。对于短时间内持续引用特定的查询而后很可能不再使用的情况,FIFO是很好的选择。
根据个人实践,内存充足时使用LRU,否则使用MEMORY(WEAK)通常能获得较好的效果。
2)
OSCACHE类型的cache值得就是使用OpenSymphony的oscache作为cache的实现方案。
OSCACHE 实现不使用 property 元素,而是在类路径的根路径中使用标准的oscache.properties 文件进行配置。在 oscache.properties文件中,您可以配置 Cache 的算法(和上面讨论的算法很类似),Cache 的大小,持久化方法(内存,文件等)和集群方法
1)使用flushOnExecute 标签的时候,启动项目的时候一直报错,报的是sqlmap的配置问题
调查了很久,最后发现问题:我最初是这样写的 :
<span style="color:#323e32;"> <cacheModel id="messageTemplate-cache" type="FIFO" readOnly="true"
serialize="true">
<flushInterval hours="24" />
</span><span style="color:#ff0000;"> <flushOnExecute statement="refreshCache"/>
<flushOnExecute statement="insert"/></span><span style="color:#323e32;">
<property name="size" value="3000" />
</cacheModel>
<select id="refreshCache">
select 1
</select></span>
可以看到红色标注的地方,我在使用的statement中没有添加namespace,主要是因为之前写sqlmap的时候都不写的,以为是默认添加,但是这边起始不是这样的。
正确的写法:
<span style="color:#323e32;"> <cacheModel id="messageTemplate-cache" type="FIFO" readOnly="true"
serialize="true">
<flushInterval hours="24" />
</span><span style="color:#ff0000;"> <flushOnExecute statement="MessageTemplate.refreshCache"/>
<flushOnExecute statement="MessageTemplate.insert"/></span><span style="color:#323e32;">
<property name="size" value="3000" />
</cacheModel>
<select id="refreshCache">
select 1
</select></span>
(七)总结
1、 感觉ibatis的缓存到了一定的时候就会有瓶颈,在实际应用中如果把数据层的cache做到应用层效果应该会更好。
2、 Ibatis设置cache,当session设为 true 的时候,缓存中存放的对象(你想查询的POJO)必须是可序列化的,即实现Serializable接口,而且只能是jdk自带的序列化。如果你有一个复杂对象属性,它也必须满足这个规则,你的整个对象树必须是可序列化的