Mybatis的缓存机制

Mybatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制,缓存可以极大的提升查询效率。

MyBatis中默认定义了两级缓存,分别是一级缓存和二级缓存。
(1) 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
(2)二级缓存需要手动开启和配置,二级缓存是基于Mapper(namespace)级别的缓存。
(3)为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一、Mybatis的一级缓存

Mybatis的缓存机制_第1张图片

  1. 什么是一级缓存,为什么使用一级缓存?

    1. 为了解决这个问题,减少资源浪费,MyBatis会在表示会话的SQLSession对象中建立一个简单的缓存,将每次查询到的结果缓存起来,当下次查询的时候,如果判断现有个完全一样的查询,会直接从缓存中将结果取出来,返回给用户,不需要再进行一次查询数据库了。
    2. 在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
    3. 每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。

2.MyBatis中的一级缓存是怎样组织的?(即SqlSession中的缓存是怎样组织的?)

SqlSession对象、Executor对象、Cache对象之间的关系如下图所示:

Mybatis的缓存机制_第2张图片 

 PerpetualCache内部是通过HashMap实现的

public class PerpetualCache implements Cache {  
	private String id;  
	private Map cache = new HashMap(); 
	public void putObject(Object key, Object value) {  
		cache.put(key, value);  
	}  
	public Object getObject(Object key) {  
		return cache.get(key);  
	}  
	public Object removeObject(Object key) {  
		return cache.remove(key);  
	}  
	public void clear() {  
		cache.clear();  
	}
}

3.一级缓存的生命周期有多大?

(1)Mybatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

(2)SqlSession调用close()方法,释放PerpetualCache对象

(3)SqlSession调用clearCache()方法,只会清空PerpetualCache对象中的数据,对象仍可使用

(4)SqlSession执行了任何一个update(),delete(),insert()方法,都会清空PerpetualCache对象中的数据,对象仍可使用

4.SQLSession一级缓存的工作流程

(1)对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;

(2)判断从Cache中根据特定的key值取的数据是否为空,即是否命中;

(3)如果命中,则直接将缓存结果返回

(4)如果没命中,则直接去数据库查询,得到查询结果,将Key值和查询到的结果分别作为key和value存储到Cache中,再将查询结果返回给用户。

5.如何确定Cache中Map的Key值?

Mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:

(1)statementId

(2)rowBounds(查询结果集中的结果范围)

(3)传递给JDBC的SQL

(4)传递给JDBC的参数值

二、Mybatis的二级缓存

二级缓存是Application级别的缓存

Mybatis的缓存机制_第3张图片 

二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、OScache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。

Mybatis的二级缓存默认是不开启的,需要手动设置开启

开启二级缓存的步骤:

(1)在总配置文件中设置Setting

Mybatis的缓存机制_第4张图片

 (2)在Mapper.xml中添加Mybatis的缓存机制_第5张图片

(3)在某条查询语句中设置useCache="true",默认为true

 (4)对象的类必须实现序列化接口

 Mybatis的缓存机制_第6张图片

 三、Cache缓存相关属性

eviction
缓存回收策略:
(1) LRU – 最近最少使用的:移除最长时间不被使用的对象。eviction的默认值 是 LRU。
(2) FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
(3) SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
(4) WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval
刷新间隔,取值单位毫秒:
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size
引用数目,取值正整数:
代表缓存最多可以存储多少个对象,太大容易导致内存溢出。
readOnly
只读,取值true/false
(1)true:只读缓存; 会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
(2)false:读写缓存; 会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

 四、Cache使用的注意事项

(1)只能在只有单表操作的表上使用缓存,不只是要保证这个表在整个系统上只有单表操作,而且和该表有关的全部操作必须在一个namespace下

(2)保证查询远远大于insert、update、delete

(3)多表操作下一定不能使用缓存

你可能感兴趣的:(mybatis,缓存,java)