缓存机制是为了减轻数据库压力,提高数据库性能。
Mybatis查询缓存分为一级缓存和二级缓存,默认开启一级缓存。
- 一级缓存是
SqlSession
级别的缓存,PerpetualCache
。 - 二级缓存是
mapper
级别的缓存。是多个SqlSession
共享的。
一、一级缓存SqlSession
级别
一级缓存是SqlSession
级别的缓存,在操作数据库时需要构造SqlSession
对象,在对象中有一个HashMap
用于存储缓存数据。不同的SqlSession
之间的缓存数据区域HashMap
是互不影响的。
Mybatis缓存机是基于id
进行缓存的,也就是说,Mybatis使用HashMap缓存数据时,是使用对象的id
作为key
,而对象作为value
保存的。
第一次以id
为1
进行查询执行了一条select
语句,第二次获取id
为1
的数据,不会再执行select
语句。
如果不执行session.commit()
,操作没有提交到数据库,此时Mybatis不会清空SqlSession
缓存。
若在第一次查询id
为的数据时执行了一条select
语句,接下来执行了一个update,delete,insert into
操作,Mybatis为了保证缓存中存储的最新信息,会清空SqlSession
缓存。
因一级缓存是SqlSession
级别的,如果在执行第一次根据id
查询后,执行了close()
方法,该方法会关闭SqlSession
缓存,第二次根据相同的id
查询,一级缓存也就是SqlSession
缓存是一个新的对象,会再次执行select
语句。
在实际的项目开发中,往往会将Mybatis
与Spring
整合,SqlSession
会交给Spring
管理,每查询结束后,Spring
会清空当前的SqlSession
释放资源,也就每次查询所使用的SqlSession
是不相同的,导致Mybatis
的一级缓存失效。
二、二级缓存mapper
级别
二级缓存是mapper
级别的缓存,是多个SqlSession
使用同一个mapper
的sql
语句去操作数据库,得到的数据会存在二级缓存区域。
二级缓存也是使用HashMap
进行数据存储的,范围比一级缓存更大,是跨SqlSession
的,多个SqlSession
可以共用二级缓存。
二级缓存是多个SqlSession
共享的,其作用域是mapper
的同一个namespace
。不同的SqlSession
两次执行相同namespace
下的sql
语句,且向sql
中传递的参数也相同,即最终执行相同的sql
语句,即第一次执行完毕会将从数据库查询到的数据写入缓存(内存),第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
当Mybatis在一级缓存中没有找到与id
对应的对象时,就会去二级缓存中查找,如果还没有,就去数据库查找。
Mybatis默认没有开启二级缓存,需要在setting
全局参数中配置开启二级缓存。开启配置如下:
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
开始当前mapper
的namespace
下的二级缓存,xxxMapper.xml
<!-- 创建一个LRU缓存,并每隔60秒刷新,最大储储512个对象,返回对象是只读 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
cache
开启当前mapper
的namespace
下的二级缓存。该元素属性设置如下:
flushInterval
刷新间隔,单位毫秒,默认不设置没有刷新间隔,在调用时刷新。size
缓存数目,需要缓存的对象数目,默认值是1024。readOnly
只读,可设置为true
或false
。默认false
,可读写,返回的是缓存对象的拷贝(通过序列化),会慢些,但安全。
使用二级缓存时,与查询结果映射的Java对象,必须实现java.io.Serializable
接口的序列化和反序列化操作。如果存在你的父类,其成员都需要实现序列化接口。
实现序列化接口是为了对缓存数据进行序列化和反序列化操作,因为二级缓存数据存储介质多样,不一定在内存,有可能是硬盘或远程服务器。
在select
中设置useCache=false
,可以禁用当前select
语句的二级缓存,即每次查询都会发出sql
查询,默认是true
即开该了二级缓存则该sql
使用二级缓存。该设置通常用于每次查询都需要最新的数据情况。