Mybatis源码研究7:缓存的设计和实现

2014年11月19日 21:02:14 酷酷的糖先森 阅读数:1020
 
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014723529/article/details/41288565

一、包概述(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

Mybatis源码研究7:缓存的设计和实现的更多相关文章

  1. Mybatis源码手记-从缓存体系看责任链派发模式与循环依赖企业级实践

    一.缓存总览 Mybatis在设计上处处都有用到的缓存,而且Mybatis的缓存体系设计上遵循单一职责.开闭原则.高度解耦.及其精巧,充分的将缓存分层,其独到之处可以套用到很多类似的业务上.这里将主要 ...

  2. myBatis源码解析-二级缓存的实现方式

    1. 前言 前面近一个月去写自己的mybatis框架了,对mybatis源码分析止步不前,此文继续前面的文章.开始分析mybatis一,二级缓存的实现.附上自己的项目github地址:https:// ...

  3. Mybatis源码分析之缓存

    一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...

  4. 【mybatis源码学习】缓存机制

    一.mybatis的缓存 一级缓存:sqlsession级别,默认开启(一个事务内有效)二级缓存:  sqlsessionFactory级别,需要手动开启,在xml配置cache节点(依赖事务的执行结 ...

  5. mybatis源码分析之走进缓存

    之前写了一篇关于mybatis缓存的读后感,想了想还是把缓存模块简单分析一下,附赠下载地址:https://github.com/MyBatis/MyBatis-3,github直接搜排名很靠前的. ...

  6. 【MyBatis源码解析】MyBatis一二级缓存

    MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...

  7. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

  8. Mybatis源码分析之Cache二级缓存原理 (五)

    一:Cache类的介绍 讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(Ser ...

  9. mybatis源码学习(三)-一级缓存二级缓存

    本文主要是个人学习mybatis缓存的学习笔记,主要有以下几个知识点 1.一级缓存配置信息 2.一级缓存源码学习笔记 3.二级缓存配置信息 4.二级缓存源码 5.一级缓存.二级缓存总结 1.一级缓存配 ...

随机推荐

  1. 【转】GnuPG使用介绍

    一.什么是 GPG 要了解什么是 GPG,就要先了解 PGP. 1991 年,程序员 Phil Zimmermann 为了避开政府监视,开发了加密软件 PGP.这个软件非常好用,迅速流传开来,成了许多 ...

  2. HDU4814——数学,模拟进制转换

    本题围绕:数学公式模拟进制转换 HDU4814 Golden Radio Base 题目描述 将一个十进制的非负整数转换成E(黄金分割数)进制的数 输入 不大于10^9的非负整数,处理到文件尾 输出 ...

  3. sql中如何获取一条数据中所有字段的名称和值

    declare ) ) --获取表的列名 ,),filename INTO #templist FROM (select cl.name as filename from sys.tables AS ...

  4. ThreadLocal(在一个线程中共享数据)

    ThreadLocal 在"事务传递Connection"参数案例中,我们必须传递Connection对象,才可以完成整个事务操作.如果不传递参数,是否可以完成?在JDK中给我们提 ...

  5. PHP——数组根据某一键值合并

    前言 其实要实现很简单直接foreach,再根据PHP中数组的特性就可以轻松实现. 步骤 这是源数据的格式 $info = [ [ "gname" => "特别关心 ...

  6. FTP服务FileZilla Server上传提示550 Permission denied

    原文地址:https://help.aliyun.com/knowledge_detail/5989224.html 相关文章 1.filezilla通过root账户远程连接管理ubuntu serv ...

  7. HTML5 自定义属性 data-*属性名一定要小写吗?

    最近学习 javascript ,参考书籍是< javascript 高级程序设计>第三版,在介绍自定义元素属性时书中给出了一个例子,如下:<div id="myDiv&q ...

  8. Subarray Sum II

    Description Given an positive integer array A and an interval. Return the number of subarrays whose ...

  9. 学习Spring-Data-Jpa(八)---定义方法查询

    1.查询策略 spring-data一共有三种方法查询策略: QueryLookupStrategy.Key.CREATE,尝试根据方法名进行创建.通用方法是从方法名中删除一组特定的前缀,然后解析该方 ...

  10. [RN] React Native 实现 FlatList上拉加载

     FlatList可以利用官方组件 RefreshControl实现下拉刷新功能,但官方没有提供相应的上拉加载的组件,因此在RN中实现上拉加载比下拉刷新要复杂一点. 不过我们仍可以通过FlatList ...