IBatis 的缓存机制

14 篇文章 0 订阅
7 篇文章 0 订阅

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

 

 

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

 

0 1  parser.addNodelet( "/sqlMap/cacheModel", new Nodelet() {
0 2  public void process(Node node) throws Exception ... {
03  Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
04  String id = state.applyNamespace(attributes.getProperty("id"));
05  String type = attributes.getProperty("type");
06  String readOnlyAttr = attributes.getProperty("readOnly");
07  Boolean readOnly = readOnlyAttr ==null || readOnlyAttr.length() <= 0 ?null : new Boolean("true".equals(readOnlyAttr));
08  String serializeAttr = attributes.getProperty("serialize");
09  Boolean serialize = serializeAttr ==null || serializeAttr.length() <= 0 ?null : new Boolean("true".equals(serializeAttr));
10  type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
11  Class clazz = Resources.classForName(type);
12  if (readOnly ==null) ...{
13  readOnly = Boolean.TRUE;
14  }

15  if (serialize ==null) ...{
16  serialize = Boolean.FALSE;
17  }

18  CacheModelConfigcacheConfig = state.getConfig().newCacheModelConfig(id,(CacheController) Resources.instantiate(clazz),readOnly.booleanValue(), serialize.booleanValue());
19  state.setCacheConfig(cacheConfig);
20  }

21  });

 

上面红色的代码很关键,它是 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) ... {
05       this.errorContext = config.getErrorContext();
06       this.cacheModel = new CacheModel();
07       SqlMapClientImpl client = config.getClient();
08       errorContext.setActivity("building a cache model");
09       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      thrownew 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 publicclass CacheModel implements ExecuteListener

 

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

 

0 1 com.ibatis.sqlmap.engine.mapping.statement.MappedStatement
0 2 publicint executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
0 3 throws SQLException ... {
04 ErrorContext errorContext = statementScope.getErrorContext();
05 errorContext.setActivity("preparing the mapped statement for execution");
06 errorContext.setObjectId(this.getId());
07 errorContext.setResource(this.getResource());
08
09 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 thrownew NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
49 }
catch (Exception e)...{
50 errorContext.setCause(e);
51 thrownew NestedSQLException(errorContext.toString(), e);
52 }

53 }

54
55 publicvoid notifyListeners() ... {
56 for (int i = 0, n = executeListeners.size(); i < n; i++)...{
57 ((ExecuteListener) executeListeners.get(i)).onExecuteStatement(this);
58 }

59 }

 

再看 CacheModel 是如何处理的:

 

 

0 1 publicvoid onExecuteStatement(MappedStatement statement) {
0 2 flush();
0 3 }
0 4
0 5 publicvoid flush() ... {
06     synchronized (this)...{
07 controller.flush(this);
08 lastFlush = System.currentTimeMillis();
09 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 publicvoid flush(CacheModel cacheModel) {
2 cache.clear();
3 }

 

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

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

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

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

 

0 1 < cacheModel id ="product-cache" imlementation ="LRU" >
0 2 < flushInterval hours ="24" />
0 3 < flushOnExecute statement ="insertProduct" />
0 4 < flushOnExecute statement ="updateProduct" />
0 5 < flushOnExecute statement ="deleteProduct" />
0 6 < property name ="size" value ="1000" />
0 7 </ cacheModel >
0 8 < statement id ="getProductList" parameterClass ="int" cacheModel ="product-cache" >
0 9 select * from PRODUCT where PRD_CAT_ID = #value#
10 </ statement >

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

 

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值