文中的内容参考至
IBATIS in action 的第九章Improving performance with caching。
入门样例
首先是一个非常简单的Caching 实例
<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掉。下面是该类型缓存使用样例。
<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类型的缓存惟一可以设置的属性就是这个最大缓存数。下面是该类型缓存使用样例。
<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,不同的是其使用使用的是“先进先出”的策略。该类型的缓存惟一可以设置的属性就是这个最大缓存数。下面是该类型缓存使用样例。
<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的使用案例
<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,例如以下这个例子
<cacheModel id="categoryCache" type="MEMORY">
…
<flushInterval hours= "12" />
…
</cacheModel>
总结
Ibatis内建了对Cache的支持,目的就是通过cache的运用来提升性能和Scalability等等。但跟App自己使用Cache一样,Ibatis对cache的使用同样要考虑集群、其他应用直接修改数据库等问题。