浅析ibatis的cache兑现
浅析ibatis的cache实现
ibatis提供四种缓存方案,LRU、FIFO、MEMORY、EHCACHE,通过定义不同的cacheModel,将数据缓存在cache中。
具体写法参考如下
一、参见com.ibatis.sqlmap.engine.builder.xml.SqlMapParser
parse在解析xml的时候,遇到一个cacheModel标签,则创建一个CacheModel的对象
并通过如上方法,成功的将cacheModel对象加入到map中缓存起来,同时为cacheModel设置缓存控制器(LRU、FIFO、MEMORY、EHCACHE),实现不同的缓存方案
因为是单例模式, SqlMapExecutorDelegate通过HashMap cacheModels ,持有了全部的cacheModel,并作为静态对象全局共享。
二、参见com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser
解析statement时,如果cache可用,获取到对应的cacheModel,执行相关的缓存操作
三、参见com.ibatis.sqlmap.engine.mapping.statement.CachingStatement
CachingStatement封装了很多query的方法,以executeQueryForObject为例
如果没从cacheModel中获取到缓存数据,则继续查询,并将查询结果放到缓存中。
从这里的代码也能看到,cacheModel是允许存在缓存对象为null的情况,因此如果查询结果为null,也会缓存起来,这里要稍加注意。
四、参加com.ibatis.sqlmap.engine.cache.CacheModel
cacheModel.getObject(cacheKey)的方法,由cacheMode定义的cacheController实现(LRU、FIFO、MEMORY、EHCACHE),cacheModel作为单例类的成员变量,可以全局共享,同样CacheController做为cacheModel的成员变量,也可以全局共享,这样CacheController持有的Map cache和List keyList,也在cacheModel可以控制的范围内全局共享了,这样就实现了缓存的效果。
这里有个有意思的地方,由于cacheModel在getObject的时候,会自动统计request和hit的次数,因此使用缓存的方式,cacheModel可以提供输出缓存命中率的方法 -- 参见 public double getHitRatio()
ibatis提供四种缓存方案,LRU、FIFO、MEMORY、EHCACHE,通过定义不同的cacheModel,将数据缓存在cache中。
具体写法参考如下
<cacheModel id="cache-name" type="LRU" readOnly="true" serialize="false"> <property name="cache-size" value="1000" /> </cacheModel> <select id="getBean" resultMap="bean" cacheModel="cache-name"> <![CDATA[select * from table]]> </select>
一、参见com.ibatis.sqlmap.engine.builder.xml.SqlMapParser
parser.addNodelet("/sqlMap/cacheModel", new Nodelet() { public void process(Node node) throws Exception { vars.currentCacheModel = new CacheModel(); vars.currentProperties = new Properties(); } });
parse在解析xml的时候,遇到一个cacheModel标签,则创建一个CacheModel的对象
vars.currentCacheModel.setControllerClassName(type); if (vars.client.getDelegate().isCacheModelsEnabled()) { vars.client.getDelegate().addCacheModel(vars.currentCacheModel); }
并通过如上方法,成功的将cacheModel对象加入到map中缓存起来,同时为cacheModel设置缓存控制器(LRU、FIFO、MEMORY、EHCACHE),实现不同的缓存方案
因为是单例模式, SqlMapExecutorDelegate通过HashMap cacheModels ,持有了全部的cacheModel,并作为静态对象全局共享。
二、参见com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser
解析statement时,如果cache可用,获取到对应的cacheModel,执行相关的缓存操作
if (cacheModelName != null && cacheModelName.length() > 0 && vars.client.getDelegate().isCacheModelsEnabled()) { CacheModel cacheModel = vars.client.getDelegate().getCacheModel(cacheModelName); return new CachingStatement(statement, cacheModel); }
三、参见com.ibatis.sqlmap.engine.mapping.statement.CachingStatement
CachingStatement封装了很多query的方法,以executeQueryForObject为例
CacheKey cacheKey = getCacheKey(request, parameterObject); cacheKey.update("executeQueryForObject"); Object object = cacheModel.getObject(cacheKey); if (object == CacheModel.NULL_OBJECT){ // This was cached, but null object = null; }else if (object == null) { object = statement.executeQueryForObject(request, trans, parameterObject, resultObject); cacheModel.putObject(cacheKey, object); } return object;
如果没从cacheModel中获取到缓存数据,则继续查询,并将查询结果放到缓存中。
从这里的代码也能看到,cacheModel是允许存在缓存对象为null的情况,因此如果查询结果为null,也会缓存起来,这里要稍加注意。
四、参加com.ibatis.sqlmap.engine.cache.CacheModel
cacheModel.getObject(cacheKey)的方法,由cacheMode定义的cacheController实现(LRU、FIFO、MEMORY、EHCACHE),cacheModel作为单例类的成员变量,可以全局共享,同样CacheController做为cacheModel的成员变量,也可以全局共享,这样CacheController持有的Map cache和List keyList,也在cacheModel可以控制的范围内全局共享了,这样就实现了缓存的效果。
这里有个有意思的地方,由于cacheModel在getObject的时候,会自动统计request和hit的次数,因此使用缓存的方式,cacheModel可以提供输出缓存命中率的方法 -- 参见 public double getHitRatio()