服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > 专题栏目 > IBATIS专题 > 查看文档

Ibaits源码解读--DataMapper的Cache

Ibatis有自己的灵活的,可扩展的Cache支持。其内置的Cache类型有三种:基于内存的,LRU(最近最少使用算法)和FIFO(先进先出)。

一.基本概念

在配置文件中Cache的配置如下:

 

    statement="insertProduct"/>

    statement="updateProduct"/>

    statement="deleteProduct"/>

 

id 用于唯一标志该cacheModel。

implementation 为ICacheController的具体实现类的全限定名或者框架内部定义的别名--LRU,FIFO,MEMORY。

缓存的flush就是重新使缓存和数据库同步,Ibatis的默认实现是清空缓存。

flushInterval 指定了cache的同步(flush)时间,单位可以指定hours,minutes,seconds等,或不指定(从不flush)。

flushOnExecute  指定在所指定的statement执行后flush缓存。比如对于一个查询语句,当执行插入,更新,删除等操作时缓存就可能存在脏数据,应该被flush。Ibatis会在DomSqlMapBuilder构造CacheModel时,将flushOnExecute中指定的statement通过foreach语句注册Trigger:cacheModel.RegisterTriggerStatement(mappedStatement),而该方法就是通过mappedStatement.Execute +=new ExecuteEventHandler(FlushHandler)为flushOnExecute中指定的statement注册了FlushHandler,也就是在执行后同步(刷新)该CacheModel。

property 指定了具体的ICacheController控制器需要的其他参数属性。

二.基本使用

    使用缓存的配置如下:

  select * from PRODUCT where PRD_CAT_ID = #value#

缓存是和具体的statement一起使用的,也就是可以为需要缓存的可执行语句指定缓存,也可以不指定。这样增加了缓存的灵活性。

一个比较基本的概念:只有查询的结果需要缓存,所以缓存一定是和select语句一起出现的(说的绝对了点,基本上吧)。而缓存的查询结果在执行了其他与该数据相关的写数据的操作后,就有可能存在脏数据。

现在还没有完全明确的是,如果引起缓存中出现脏数据的mappedSatatement不在当前的配置文件中,是否可以通过全限定名来访问该mappedSatatement(理论上应该可以,需要试验)。

三.原理

对于三种算法:

1.基于内存

    基于内存的利用了WeakReference,也就是弱引用。同时,Ibatis自己构造了StrongReference类型,java中还有SOFT类型(.NET中不支持)。内存缓存适用于简单应用和服务器物理内存紧张的环境。它的将对象放入缓存和从缓存中取出对象的算法如下:

         public object this[object key]

         {

              get

              {

                   object value = null;

                   object reference = _cache[key];

                   if (reference != null)

                   {

                       if (reference is StrongReference)

                       {

                            value = ((StrongReference) reference).Target;

                       }

                       else if (reference is WeakReference)

                       {

                            value = ((WeakReference) reference).Target;

                       }

                   }                 

                   return value;

              }

              set

              {

                   object reference = null;

                   if (_cacheLevel.Equals(MemoryCacheLevel.Weak))

                   {

                       reference = new WeakReference(value);

                   }

                   else if (_cacheLevel.Equals(MemoryCacheLevel.Strong))

                   {

                       reference = new StrongReference(value);

                   }

                  _cache[key] = reference;   

             

              }

         }

也就是,区分了是弱引用还是强引用。cacheLevel默认为WEAK,可以在配置文件中配置。

2.LRU

对于LRU算法,实现如下:

         public object this[object key]

         {

              get

              {

                   _keyList.Remove(key);

                   _keyList.Add(key);

                   return _cache[key];

              }

              set

              {

                   _cache[key] = value;

                   _keyList.Add(key);

                   if (_keyList.Count > _cacheSize)

                   {

                       object oldestKey = _keyList[0];

                       _keyList.Remove(0);

                       _cache.Remove(oldestKey);

                   }       

              }

         }

也就是,每次取一次缓存都会将该键首先删除然后加入的键list最后,设置缓存对象时,如果缓存大小大于预定大小,将会删除键list的第0个键值。这样就实现了LRU。

3.FIFO

对于FIFO,算法就比较简单了,只是省去了在LRU中获取缓存对象时在存放键(key)的列表中,先删除再添加到list最后的步骤:

                   _keyList.Remove(key);

                   _keyList.Add(key);

其他 与LRU一样,所以就是先进先出(永远是最先加入的最先被删除)。

     CacheModel