IBatis 的缓存机制之 Select Query缓存

 

原文地址:http://lifei114.javaeye.com/admin/blogs/581795

 

IBatis 的缓存机制之 Select Query缓存

 

可以按下面的代码在你的 SqlMap.xml 里配置,如下:

 

<cacheModelid="users-cache"imlementation="LRU"readOnly="true"serialize="true">
<flushIntervalhours="24"/>
<flushOnExecutestatement="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 来解析这个配置的,代码如下:

 

  1. private void addCacheModelNodelets() {  
  2.    parser.addNodelet("/sqlMap/cacheModel"new Nodelet() {  
  3.      public void process(Node node) throws Exception {  
  4.        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());  
  5.        String id = state.applyNamespace(attributes.getProperty("id"));  
  6.        String type = attributes.getProperty("type");  
  7.        String readOnlyAttr = attributes.getProperty("readOnly");  
  8.        Boolean readOnly = readOnlyAttr == null || readOnlyAttr.length() <= 0 ? null : new Boolean("true".equals(readOnlyAttr));  
  9.        String serializeAttr = attributes.getProperty("serialize");  
  10.        Boolean serialize = serializeAttr == null || serializeAttr.length() <= 0 ? null : new Boolean("true".equals(serializeAttr));  
  11.        type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);  
  12.        Class clazz = Resources.classForName(type);  
  13.        if (readOnly == null) {  
  14.          readOnly = Boolean.TRUE;  
  15.        }  
  16.        if (serialize == null) {  
  17.          serialize = Boolean.FALSE;  
  18.        }  
  19.        CacheModelConfig cacheConfig = state.getConfig().newCacheModelConfig(id, (CacheController) Resources.instantiate(clazz), readOnly.booleanValue(), serialize.booleanValue());  
  20.        state.setCacheConfig(cacheConfig);  
  21.      }  
  22.    });  
  23.    parser.addNodelet("/sqlMap/cacheModel/end()"new Nodelet() {  
  24.      public void process(Node node) throws Exception {  
  25.        state.getCacheConfig().setControllerProperties(state.getCacheProps());  
  26.      }  
  27.    });  
  28.    parser.addNodelet("/sqlMap/cacheModel/property"new Nodelet() {  
  29.      public void process(Node node) throws Exception {  
  30.        state.getConfig().getErrorContext().setMoreInfo("Check the cache model properties.");  
  31.        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());  
  32.        String name = attributes.getProperty("name");  
  33.        String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());  
  34.        state.getCacheProps().setProperty(name, value);  
  35.      }  
  36.    });  
  37.    parser.addNodelet("/sqlMap/cacheModel/flushOnExecute"new Nodelet() {  
  38.      public void process(Node node) throws Exception {  
  39.        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());  
  40.        String statement = childAttributes.getProperty("statement");  
  41.        state.getCacheConfig().addFlushTriggerStatement(statement);  
  42.      }  
  43.    });  
  44.    parser.addNodelet("/sqlMap/cacheModel/flushInterval"new Nodelet() {  
  45.      public void process(Node node) throws Exception {  
  46.        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());  
  47.        try {  
  48.          int milliseconds = childAttributes.getProperty("milliseconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("milliseconds"));  
  49.          int seconds = childAttributes.getProperty("seconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("seconds"));  
  50.          int minutes = childAttributes.getProperty("minutes") == null ? 0 : Integer.parseInt(childAttributes.getProperty("minutes"));  
  51.          int hours = childAttributes.getProperty("hours") == null ? 0 : Integer.parseInt(childAttributes.getProperty("hours"));  
  52.          state.getCacheConfig().setFlushInterval(hours, minutes, seconds, milliseconds);  
  53.        } catch (NumberFormatException e) {  
  54.          throw new RuntimeException("Error building cache in '" + "resourceNAME" + "'.  Flush interval milliseconds must be a valid long integer value.  Cause: " + e, e);  
  55.        }  
  56.      }  
  57.    });  
  58.  } 

 带缓存的SQL具体的执行是由类:CachingStatement  来执行,如要执行executeQueryForList动作,其执行的代码如下:

 

  1. public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject, int skipResults, int maxResults)  
  2.     throws SQLException {  
  3.   CacheKey cacheKey = getCacheKey(statementScope, parameterObject);  
  4.   cacheKey.update("executeQueryForList");  
  5.   cacheKey.update(skipResults);  
  6.   cacheKey.update(maxResults);  
  7.   Object listAsObject = cacheModel.getObject(cacheKey);  
  8.   List list;  
  9.   if(listAsObject == CacheModel.NULL_OBJECT){  
  10.     // The cached object was null  
  11.     list = null;  
  12.   }else if (listAsObject == null) {  
  13.     list = statement.executeQueryForList(statementScope, trans, parameterObject, skipResults, maxResults);  
  14.     cacheModel.putObject(cacheKey, list);  
  15.   }else{  
  16.     list = (List) listAsObject;  
  17.   }  
  18.   return list;  

中去,再次使用时就直接返回缓存里的数据了。

这里面的 CacheKey 很有意思,Ibatis 是按照 SQL 加参数并加参数个数进行 Hash 组成一个 Key。因此我们的查询中 SQL的参数变化的频率太多时,使用缓存的效果将十分不明显,

甚至可能取得相反的效果,每次查询缓存也是需要时间的。

具体项目中如何使用缓存我认为具体问题具体分析,不要盲目相信科学神话,“大家都在用的东西不一定就适合自己用”

  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;
  }
阅读更多
个人分类: Java iBatis Cache
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭