Ibaitsnet源码解读(4)--DataMapper的Cache

来源:互联网 发布:淘宝自动回复优美语句 编辑:程序博客网 时间:2024/04/30 03:26

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

一.基本概念

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

 <flushonexecute  statement="insertProduct"/>  <flushonexecute  statement="updateProduct"/>  <flushonexecute  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是Cache的Facade,CacheModel负责通过配置文件实例并初始化具体的Cache控制器(实现了ICacheController的类),同时提供public void RegisterTriggerStatement(IMappedStatement mappedStatement)方法,为那些执行后可能会产生脏数据的语句注册触发器,让他们在执行后同步缓存。

     SqlMapper提供了最外层的缓存管理和访问的方法:internal void AddCache(CacheModel cache) ,internal CacheModel GetCache(string name) ,这两个方法在通过DomSqlMapBuilder构造SqlMapper实例时调用。另外两个方法public void FlushCaches() ,public string GetDataCacheStats() 提供给客户端调用。

四.扩充
    Ibatis的cache框架是可扩展的,必须要遵循的是我们必须自定义一个实现ICacheController接口缓存控制器,实现自己的缓存算法,然后相关的配置在xml配置文件中指定就可以。
五.总结
    Ibatia的缓存框架还是比较灵活,可扩充的,但同时,框架本身提供的缓存实现类还比较简单。比如flush时将会清空缓存,这样可能不够强大。有可能按需要实现自己的缓存控制器实现。

原创粉丝点击