Mybatis源码研究7:缓存的设计和实现
Mybatis源码研究7:缓存的设计和实现
一、包概述(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
最新文章
- C学习
- office2016 软件全集 官方下载免费完整版(含破解文件)不含垃圾软件 win10完美激活
- 修改Window的hosts文件提示“该文件被其他程序占用”解决方案
- 【阿里云产品公测】大数据下精确快速搜索OpenSearch
- 在Toast里面显示图片
- Leetcode OJ : Repeated DNA Sequences hash python solution
- git fetch 拉取而不合并
- 用OpenGL简单编写的一个最简单贪吃蛇游戏
- MATLAB 常用形态学操作函数
- 很多人都在埋怨没有遇到好的团队,但好的团队不可能凭空出现,一流的团队不能仅靠团队成员努力,作为Leader,要有可行的规划,并坚定地执行、时势地调整(转)
- 应用程序框架实战十三:DDD分层架构之我见(转)
- 【小技巧】C#的saveFileDialog和openFileDialog的用法总结
- iOS模式详解—「runtime面试、工作」看我就 &#128018; 了 ^_^.
- 关于spring boot中 EmbeddedServletContainerCustomizer
- 添加自己的component
- Linux服务器更换主板后,网卡识别失败的处理方法
- Quick Noodle Physics in Blender Tutorial
- Rx编程的第一步是将native对象转换为monad对象
- python+selenium安装方法
- [C#]记录程序耗时的方法【转发】
热门文章
- eclipse设置代码折叠展开快捷键
- 注入 Istio sidecar
- SpringBoot项目打成jar在linux后台运行
- mysql where 1
- 【统计难题】【HDU - 1251】【map打表或字典树】【字典树模板】
- Calendar.getInstance()获取指定时间点(定时)
- Spring Boot-初学01 -使用Spring Initializer快速创建Spring Boot项目 -@RestController+spEL -实现简单SpringBoot的Web页面
- Java基础(八 前面补充)
- 猎豹全球智库执行院长:中国App出海的三大规律和最具代表的五大垂直品类
- 前端知识--控制input按钮的可用和不可用