IBatis 的缓存机制

缓存机制,也是基于 Key-Value 的方式,确定了 Key 的来龙去脉能很好的认识缓存的生存周期。
从配置文件解析说起:

   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); 
   } 
   });
上面红色的代码很关键,它是 Statement 中,对应的Cache 的Key 就是它。返回的对象:CacheModelConfig,对应的部分代码如下:

0 1 private ErrorContext errorContext;
0 2    private CacheModel cacheModel;
0 3
0 4      CacheModelConfig(SqlMapConfiguration config, String id, CacheController controller, boolean readOnly, boolean serialize) ... {
0 5        this .errorContext = config.getErrorContext();
0 6        this .cacheModel = new CacheModel();
0 7        SqlMapClientImpl client = config.getClient();
0 8        errorContext.setActivity("building a cache model" );
0 9        cacheModel.setReadOnly(readOnly);
10   cacheModel.setSerialize(serialize);
11       errorContext.setObjectId(id + " cache model" );
12       errorContext.setMoreInfo("Check the cache model type." );
13       cacheModel.setId(id);
14       cacheModel.setResource(errorContext.getResource());
15        try ... {
16          cacheModel.setCacheController(controller);
17         } catch (Exception e) ... {
18       throw new RuntimeException("Error setting Cache Controller Class. Cause: " + e, e);
19   }
20   errorContext.setMoreInfo("Check the cache model configuration." );
21 if (client.getDelegate().isCacheModelsEnabled()) ... {
22   client.getDelegate().addCacheModel(cacheModel);
23   }
24   errorContext.setMoreInfo(null );
25   errorContext.setObjectId(null );
26   }
注意红色的代码,再来看看 CacheModel,如下:

1  public class CacheModel implements ExecuteListener
ExecuteListener 是一个监听器,它在 Update、insert,delete 操作执行后,触发些事件:源头如下:

0 1  com.ibatis.sqlmap.engine.mapping.statement.MappedStatement
0 2  public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
0 3   throws SQLException ... {
0 4  ErrorContext errorContext = statementScope.getErrorContext();
0 5  errorContext.setActivity("preparing the mapped statement for execution" );
0 6  errorContext.setObjectId(this .getId());
0 7  errorContext.setResource(this .getResource());
0 8 
0 9  statementScope.getSession().setCommitRequired(true );
10 
11   try ... {
12  parameterObject = validateParameter(parameterObject);
13 
14  Sql sql = getSql();
15 
16  errorContext.setMoreInfo("Check the parameter map." );
17  ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);
18 
19  errorContext.setMoreInfo("Check the result map." );
20  ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
21 
22  statementScope.setResultMap(resultMap);
23  statementScope.setParameterMap(parameterMap);
24 
25  int rows = 0;
26 
27  errorContext.setMoreInfo("Check the parameter map." );
28  Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
29 
30  errorContext.setMoreInfo("Check the SQL statement." );
31  String sqlString = sql.getSql(statementScope, parameterObject);
32 
33  errorContext.setActivity("executing mapped statement" );
34  errorContext.setMoreInfo("Check the statement or the result map." );
35  rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);
36 
37  errorContext.setMoreInfo("Check the output parameters." );
38   if (parameterObject != null ) ... {
39  postProcessParameterObject(statementScope, parameterObject, parameters);
40  }
41 
42  errorContext.reset();
43  sql.cleanup(statementScope);
44  notifyListeners();
45  return rows;
46    } catch (SQLException e) ... {
47  errorContext.setCause(e);
48  throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
49    } catch (Exception e) ... {
50  errorContext.setCause(e);
51  throw new NestedSQLException(errorContext.toString(), e);
52  }
53  }
54 
55   public void notifyListeners() ... {
56   for (int i = 0, n = executeListeners.size(); i < n; i++) ... {
57  ((ExecuteListener) executeListeners.get(i)).onExecuteStatement(this );
58  }
59  }
再看 CacheModel 是如何处理的:

0 1  public void onExecuteStatement(MappedStatement statement) {
0 2  flush();
0 3  }
0 4 
0 5   public void flush() ... {
0 6       synchronized (this ) ... {
0 7  controller.flush(this );
0 8  lastFlush = System.currentTimeMillis();
0 9   if ( log.isDebugEnabled() ) ... {
10  log("flushed" , false , null );
11  }
12  }
13  }
controller 是实现以下接口的类

    public interface CacheController

实现以下几种:

    FifoCacheController

    LruCacheController

    MemoryCacheController

    OSCacheController

再看看具体的实现,如MemoryCacheController的:

private Map cache = Collections.synchronizedMap(new HashMap());

1  public void flush(CacheModel cacheModel) {
2  cache.clear();
3  }

其它的几种实现,也基本大致如此,不在具体贴代码了。

从上面的代码分析可以看出 IBatis 的缓存的更新机制大概如下:

执行 update,insert,delete 等操作时,触发对应的事件,注册的事件响应此操作,根据XML配置的缓存,对其数据做清空操作,也就是这个缓存中的数据全部清空,而不是

清空某一个 Key对应的值,即如我更新了一个 id= 5 的数据,则这个缓存中的数据全部将清空。这样倒很简单也很彻底,由此带来的问题就很多了,如果你的 update 等相关的操作太频繁了,这里的缓存则失去意义,且加大了系统本身的开销。因此,我认为对于更新不是很频繁的数据可以用 IBatis 自身的缓存机制,如果是很频繁的数据就不要使用 IBatis 自身的缓存。举例说明:

 < cacheModel id ="product-cache" imlementation ="LRU" > 
< flushInterval hours ="24" />
< flushOnExecute statement ="insertProduct" /> 
  < flushOnExecute statement ="updateProduct" />
 < flushOnExecute statement ="deleteProduct" /> 
  < property name ="size" value ="1000" /> 
  </ cacheModel >
 < statement id ="getProductList" parameterClass ="int" cacheModel ="product-cache" > 
  select * from PRODUCT where PRD_CAT_ID = #value# 
  </ statement >

如果你配置了以上操作,如果做了  insert_product,updateProduct,deleteProduct 中的任何一个操作,都将清空缓存 product-cache 中的所有数据,也就是 getProductList 方法将执行数据库操作,不能从缓存中获取数据。

最后一句,大家不要对 IBatis 的缓存抱太大的希望,虽然我们的系统中使用的是 IBatis

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值