IBatis 的缓存机制之 Select Query缓存
可以按下面的代码在你的 SqlMap.xml 里配置,如下:
<cacheModel id="users-cache" imlementation="LRU" readOnly="true" serialize="true">
<flushInterval hours="24"/>
<flushOnExecute statement="users.update"/>
<property name="size" value="1000" />
</cacheModel>
<statement id="findUsers" parameterClass="int" cacheModel="users-cache">
select * from users where member_id = #value#
</statement>
我们来跟踪一下代码,看 IBatis 是如何实现缓存的,
还是由类:SqlMapParser 来解析这个配置的,代码如下:
private void addCacheModelNodelets() {
parser.addNodelet("/sqlMap/cacheModel", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String id = state.applyNamespace(attributes.getProperty("id"));
String type = attributes.getProperty("type");
String readOnlyAttr = attributes.getProperty("readOnly");
Boolean readOnly = readOnlyAttr == null || readOnlyAttr.length() <= 0 ? null : new Boolean("true".equals(readOnlyAttr));
String serializeAttr = attributes.getProperty("serialize");
Boolean serialize = serializeAttr == null || serializeAttr.length() <= 0 ? null : new Boolean("true".equals(serializeAttr));
type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
Class clazz = Resources.classForName(type);
if (readOnly == null) {
readOnly = Boolean.TRUE;
}
if (serialize == null) {
serialize = Boolean.FALSE;
}
CacheModelConfig cacheConfig = state.getConfig().newCacheModelConfig(id, (CacheController) Resources.instantiate(clazz), readOnly.booleanValue(), serialize.booleanValue());
state.setCacheConfig(cacheConfig);
}
});
parser.addNodelet("/sqlMap/cacheModel/end()", new Nodelet() {
public void process(Node node) throws Exception {
state.getCacheConfig().setControllerProperties(state.getCacheProps());
}
});
parser.addNodelet("/sqlMap/cacheModel/property", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().getErrorContext().setMoreInfo("Check the cache model properties.");
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
state.getCacheProps().setProperty(name, value);
}
});
parser.addNodelet("/sqlMap/cacheModel/flushOnExecute", new Nodelet() {
public void process(Node node) throws Exception {
Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String statement = childAttributes.getProperty("statement");
state.getCacheConfig().addFlushTriggerStatement(statement);
}
});
parser.addNodelet("/sqlMap/cacheModel/flushInterval", new Nodelet() {
public void process(Node node) throws Exception {
Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
try {
int milliseconds = childAttributes.getProperty("milliseconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("milliseconds"));
int seconds = childAttributes.getProperty("seconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("seconds"));
int minutes = childAttributes.getProperty("minutes") == null ? 0 : Integer.parseInt(childAttributes.getProperty("minutes"));
int hours = childAttributes.getProperty("hours") == null ? 0 : Integer.parseInt(childAttributes.getProperty("hours"));
state.getCacheConfig().setFlushInterval(hours, minutes, seconds, milliseconds);
} catch (NumberFormatException e) {
throw new RuntimeException("Error building cache in '" + "resourceNAME" + "'. Flush interval milliseconds must be a valid long integer value. Cause: " + e, e);
}
}
});
}
带缓存的SQL具体的执行是由类:CachingStatement 来执行,如要执行executeQueryForList动作,其执行的代码如下:
public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject, int skipResults, int maxResults)
throws SQLException {
CacheKey cacheKey = getCacheKey(statementScope, parameterObject);
cacheKey.update("executeQueryForList");
cacheKey.update(skipResults);
cacheKey.update(maxResults);
Object listAsObject = cacheModel.getObject(cacheKey);
List list;
if(listAsObject == CacheModel.NULL_OBJECT){
// The cached object was null
list = null;
}else if (listAsObject == null) {
list = statement.executeQueryForList(statementScope, trans, parameterObject, skipResults, maxResults);
cacheModel.putObject(cacheKey, list);
}else{
list = (List) listAsObject;
}
return list;
}
上面的代码很明显,如果在缓存中存在此数据就直接返回此数据,如果没有找到则执行具体的查询操作,并将查询后的结果缓存到缓存中去,再次使用时就直接返回缓存里的数据了。
这里面的 CacheKey 很有意思,Ibatis 是按照 SQL 加参数并加参数个数进行 Hash 组成一个 Key。因此我们的查询中 SQL的参数变化的频率太多时,使用缓存的效果将十分不明显,
甚至可能取得相反的效果,每次查询缓存也是需要时间的。至于 IBatis 何时更新缓存里的数据,请参看我之前写的这遍文章 IBatis 的缓存机制( http://lifei114.iteye.com/admin/blogs/581795)
具体项目中如何使用缓存我认为具体问题具体分析,不要盲目相信科学神话,“大家都在用的东西不一定就适合自己用”,以上供大家参考,欢迎大家一起讨论,我的 QQ: 535043378 ,最近加的人太多请注明 "JavaEye"。
r
分享到:
相关推荐
关于iBATIS缓存的一个内部交流文档 一.缓存知识介绍 二.iBATIS高速缓存介绍 三.配置iBATIS缓存
如何解决动态数据表名,动态字段名情况下,由ibatis缓存select字段而引起的字段找不到的情况?以下是最简单的解决办法! 本文中内容真实可靠,保证用户很快掌握
iBATIS缓存的使用方法
ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园ibatis缓存介绍 - 勇泽 - 博客园
Java ibatis缓存技术,ibatis缓存的详细解释 值得学习!
ibatis 数据缓存,帮你了解ibatis的数据缓存机制。
ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网ibatis 缓存 - 24小时学习网
ibatis 缓存配置策略,学习篇 • iBatis对查询结果集进行本地缓存。 • Cache的key由haskcode、checksum、查询参数、sqlmap Id、sql语句、调用方法名等构成。由此可以看出,不同的参数会有不同的Key。注意,他不是以...
Java_ibatis缓存技术
NULL 博文链接:https://mov-webhobo.iteye.com/blog/1672240
iBATIS缓存介绍[借鉴].pdf
ibatis 数据缓存,讨论了ibatis 数据缓存方面的概念,即用法,用到ibatis 数据缓存的可以参考一下
NULL 博文链接:https://sunfish.iteye.com/blog/1493410
Oscache.jar包 博文链接:https://dangzhao.iteye.com/blog/193572
ibatis学习 ibatis总结 ibatis ibatis ibatis
spring+ibatis+oracle分页缓存源码
ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料