1、mybatis缓存机制
mybatis为减轻数据库压力,提高数据库性能。提供了两级缓存机制:
一级缓存:
SqlSession级别的缓存,缓存的数据只在SqlSession内有效。
一级缓存mybatis已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个基于 PerpetualCache的HashMap 本地缓存数据结构,用于缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的。
二级缓存:
mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的。
二级缓存需要我们手动开启。(全局级别) 二级缓存是mapper级别的缓存,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。
2、一级缓存
一级缓存原理:
第一次查询用户id为1的用户信息,先去缓存中查询是否有id为1的用户信息,如果没有,从数据库中查询用户信息。得到用户信息后在将用户信息储存到一级缓存中。
如果sqlSession去执行commit操作(插入、更新、删除),清空sqlSession中的一级缓存,保证缓存中始终保存的是最新的信息,避免脏读。
第二次查询用户id为1的用户信息,先去缓存中查询是否有id为1的用户信息,如缓存中有,直接从缓存中获取。
注意:两次查询须在同一个sqlsession中完成,否则将不会走mybatis的一级缓存。在mybatis与spring进行整合开发时,事务控制在service中进行,重复调用两次servcie将不会走一级缓存,因为在第二次调用时session方法结束,SqlSession就关闭了
注意事项:
mybatis默认是开启一级缓存,不需要配置
如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中存的数据永远和数据库中一致,避免出现脏读
一个SqlSession结束后那么它里面的一级缓存也就不存在了。
mybatis的缓存是基于 [ namespace:sql语句:参数 ] 来进行缓存的。意思就是,SqlSession的HashMap存储缓存数据时,是使用 [ namespace:sql:参数 ] 作为key,查询返回的语句作为value保存的。
3、二级缓存
二级缓存与一级缓存原理相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper ( Namespace ),并且可自定义存储源,如 Ehcache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。
二级缓存可以设置返回的缓存对象策略:
readOnly=“true”(只读):MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户 。不安全,速度快。
readOnly=“false”(读写,默认):MyBatis 觉得获取的数据可能会被修改,MyBatis 会利用序列化或反序列化的技术克隆一份新的数据。安全,速度相对慢。
二级缓存是基于映射文件的缓存(namespace),缓存范围比一级缓存更大,不同的SQLSession可以访问二级缓存的内容。哪些数据放入二级缓存需要自己指定
二级缓存的具体流程:
当一个sqlseesion执行了一次select后,关闭此session的时候,会将查询结果缓存到二级缓存
当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能
注意事项:
如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
mybatis的缓存是基于[ namespace:sql语句:参数 ]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[ namespace:sql:参数 ]作为key,查询返回的语句作为value保存的。
4、开启mybatis二级缓存
4.1.1、通过application.yml配置二级缓存开启
# mybatis相关配置
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#开启MyBatis的二级缓存
cache-enabled: true
4.1.2、通过MyBatis配置文件开启二级缓存【在MyBatis-config.xml 文件中添加如下代码】
<setting name="cacheEnabled" value="true"/>
4.2、在 xxxMapper.xml 文件中添加
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"/>
4.3、属性解释
eviction:缓存的回收策略,默认的是 LRU。
LRU - 最近最少使用,移除最长时间不被使用的对象。
FIFO - 先进先出,按对象进入缓存的顺序来移除它们。
SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象。
WEAK - 弱引用,更积极地移除基于垃圾收集器和弱引用规则的对象。
flushInterval:缓存刷新间隔。缓存多长时间清空一次,默认不清空,设置一个毫秒值。
readOnly:是否只读。
true(只读):
false(读写,默认)
size:缓存存放多少个元素。
type:指定自定义缓存的全类名(实现 Cache 接口即可)。PS:要使用二级缓存,对应的 POJO 必须实现序列化接口 。
4.4、是否使用一级缓存
如果一条句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为 false,如:
<select id="selectUserById" resultMap="map" useCache="false">
二级缓存默认会在 insert、update、delete 操作后刷新缓存。但可以手动配置不更新缓存
<update id="updateUserById" parameterType="User" flushCache="false">