设为首页 收藏本站
查看: 1045|回复: 0

[经验分享] Mybatis源码研究7:缓存的设计和实现

[复制链接]

尚未签到

发表于 2016-11-27 11:35:16 | 显示全部楼层 |阅读模式
  一、包概述(org.apache.ibatis.cache)
  本包包含了Mybatis框架的缓存接口的定义和实现。

本包只引用了Mybatis的io包的Resources,不依赖于任何第三方库。

Mybatis的其它包大量引用了本包中的类和接口,即严重依赖于本包。


二、类和接口概述

缓存框架按照 Key-Value方式存储,Key的生成采取规则为:[hashcode:checksum:mappedStementId:offset:limit:executeSql:queryParams]。


Cache接口定义了缓存接口。
  
CacheKey定义了缓存的Key。
PerpetualCache直接实现了Cache接口。

FifoCache,LoggingCache,LruCache,ScheduledCache,SerializedCache,SoftCache,SynchronizedCache,
TransactionalCache,WeakCache 采用装饰模式实现Cache接口。

采用装饰模式,一个个包装起来,形成一个链,典型的就是SynchronizedCache->LoggingCache->SerializedCache->LruCache->PerpetualCache,通过链起来达到功能增加。

CacheException定义了缓存异常。

三、缓存接口的定义

  public interface Cache {
// 缓存实现类的id
String getId();
  // 缓存的对象的个数
int getSize();
  // 放入一个缓存对象
void putObject(Object key, Object value);
  // 获得一个缓存对象
Object getObject(Object key);
  // 删除一个缓存对象
Object removeObject(Object key);
  // 清空缓存对象
void clear();
  // 获取读写锁
ReadWriteLock getReadWriteLock();
  }
  
四、缓存Key的设计

一般缓存框架的数据结构基本上都是 Key-Value方式存储。 MyBatis对于其Key的生成采取规则为:
  [hashcode:checksum:mappedStementId :offset:limit:executeSql:queryParams]。
  (待深入研究和完善)
  
五、缓存实现类和包装类

  实现类:PerpetualCache,永久缓存,一旦存入就一直保持,内部就是一个HashMap,所有方法基本就是直接调用HashMap的方法。
  内部维护一个Map数据结构,private Map<Object, Object> cache = new HashMap<Object, Object>();

  包装类:
  FifoCache:先进先出缓存,内部就是一个链表,将链表开头元素(最老)移除。
  LoggingCache:日志缓存,添加功能:取缓存时打印命中率。
  LruCache:最近最少使用缓存,核心就是覆盖 LinkedHashMap.removeEldestEntry方法,返回true或false告诉 LinkedHashMap要不要删除此最老键值。
LinkedHashMap内部其实就是每次访问或者插入一个元素都会把元素放到链表末尾,这样不经常访问的键值肯定就在链表开头啦。
  ScheduledCache:定时调度缓存, 目的是每一小时清空一下缓存。
  SerializedCache:序列化缓存,用途是先将对象序列化成2进制,再缓存向缓存中 put或get数据时的序列化及反序列化处理。、
  SoftCache:软引用缓存,核心是SoftReference。
  SynchronizedCache:同步缓存,防止多线程问题。
核心: 加读写锁, ReadWriteLock.readLock().lock()/unlock() ,ReadWriteLock.writeLock().lock()/unlock()
  对于 Lock机制来说,其分为 Read 和 Write 锁,其 Read 锁允许多个线程同时持有,而 Write 锁,一次能被一个线程持有,如果当 Write 锁没有释放,其它需要 Write的线程只能等待其释放才能去持有。
  TransactionalCache:
  事务缓存,一次性存入多个缓存,移除多个缓存 。

我们可以看到在TransactionalCache类里也维护着两个HashMap:
entriesToAddOnCommit和entriesToRemoveOnCommit。

当在TransactionalCacheManager中调用putObject和removeObject方法的时候并不是马上就把对象存放到缓存或者从缓存中删除 ,而是先把这个对象放到这两个HashMap之中的一个里,然后当执行commit方法时再真正地把对象存放到缓存或者从缓存中删除。

现在我们应该可以明白为TransactionalCacheManager和TransactionalCache这两个类要加上事务的前缀了,因为commit方法是一个原子操作,一次会操作多个对象,要么一起成功,要么就一起失败。
  WeakCache:弱引用缓存,核心是WeakReference。

六、缓存实现的问题和解决方案(待深入研究和完善)

  问题:
  1.作为缓存中对象的key是它的CacheKey对象。

不得不说这是一个失败的设计,key值的类型是String类型就已经足够了,完全没有必要用对象类型来做key值的类型。

因为内存空间是有限的,要在有限的空间中尽可能地存放更多的内容,就需要key值在保证唯一性的情况下空间占的越小越好。
  2.myBatis的读写锁有写饥渴问题等,这些问题都会给性能造成影响。

所以还是不建议在生产环境中使用iBatis或者myBatis自带的二级缓存,只使用他们的ORM功能,而二级缓存还是交给Memcached等其它缓存框架来实现吧。
  
memcache:http://baike.baidu.com/view/1193094.htm

oscache:http://baike.baidu.com/view/1835163.htm

ehcache:http://baike.baidu.com/view/1866754.htm

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-306161-1-1.html 上篇帖子: Spring整合mybatis整合的两种映射器细节 下篇帖子: MyBatis系列目录--4. MyBatis别名、字段冲突、动态sql、日志、xml其他组件等若干优化
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表