Mybatis之缓存机制

Mybatis之缓存机制

一 概述

MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存
  1. 一级缓存和二级缓存
    (1) 默认情况下,只有一级缓存(SqlSession级别的缓存, 也称为本地缓存)开启。
    (2)二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    (3)为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

二 一级缓存

  1. 一级缓存介绍
    (1)一级缓存(local cache), 即本地缓存, 作用域默认 为sqlSession。当 Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。
    (2)本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域。
    (3)在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置
    localCacheScope:SESSION | STATEMENT,默认值是SESSION
    说明:Mybatis利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询,默认值为Session,这种情况下会缓存一个会话中执行的所有查询。若是STATEMENT,本地会话仅用在语句执行上,对相同SqlSession的不同调用将不会共享数据
  2. 一级缓存演示&失效情况
    (1)同一次会话期间只要查询过的数据都会保存在当 前SqlSession的一个Map中
    key:hashCode+查询的SqlId+编写的sql查询语句+参数
    (2)一级缓存失效的四种情况
    不同的SqlSession对应不同的一级缓存
    ② 同一个SqlSession但是查询条件不同
    ③ 同一个SqlSession两次查询期间执行了任何一次增删改操作
    ④ 同一个SqlSession两次查询期间手动清空了缓存

三 二级缓存

  1. 概述
    (1)二级缓存:全局作用域缓存
    (2)二级缓存默认不开启,需要手动配置
    (3)MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口
    (4)二级缓存在 SqlSession 关闭或提交之后才会生效

  2. 使用步骤
    (1)在全局配置文件中开启二级缓存

 <setting name= "cacheEnabled" value="true"/> 
(2)在需要使用二级缓存的映射文件处使用cache配置缓存  **<cache />**
(3)**POJO需要实现Serializable接口**

四 缓存属性和设置

  1. 缓存相关属性
    (1)eviction=“FIFO”:缓存回收策略
    ① LRU – 最近最少使用的:移除最长时间不被使用的对象。
    ② FIFO – 先进先出:按对象进入缓存的顺序来移除它们
    ③ SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象
    ④ WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
    ⑤ 默认的是 LRU
    (2)flushInterval:刷新间隔,单位毫秒
    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
    (3) size:引用数目,正整数
    代表缓存最多可以存储多少个对象,太大容易导致内存溢出
    (4)readOnly:只读,true,false
    ① true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。
    ② false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是false
  2. 缓存相关设置
    (1)全局setting的cacheEnable
    配置二级缓存的开关。一级缓存一直是打开的
    (2)select标签的useCache属性
    配置这个select是否使用二级缓存。一级缓存一直是使用的
    (3)sql标签的flushCache属性
    增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。 查询默认flushCache=false
    (4)sqlSession.clearCache()
    只是用来清除一级缓存
    (5)当在某一个作用域 (一级缓存Session/二级缓存 Namespaces) 进行了 C/U/D 操作后,默认该作用域下所 有 select 中的缓存将被clear

五 整合第三方缓存

  1. EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider
  2. MyBatis定义了Cache接口方便我们进行自定义扩展。
    步骤:
    (1)导入ehcache包,以及整合包,日志包

    ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
    (2)编写ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
    
        <!--持久化磁盘路径-->
        <diskStore path="D:\ehcache"/>  
    
    
        <!--默认缓存设置-->
        <defaultCache maxElementsInMemory="1000"
                       eternal="false"
                       timeToIdleSeconds="3600"
                       timeToLiveSeconds="0"
                       overflowToDisk="true"
                       maxElementsOnDisk="10000"
                       diskPersistent="false"
                       diskExpiryThreadIntervalSeconds="120"
                       memoryStoreEvictionPolicy="FIFO"
        />
         
    
        <!--
            <cache     name 缓存名唯一标识
                       maxElementsInMemory="1000" 内存中最大缓存对象数
                       eternal="false" 是否永久缓存
                       timeToIdleSeconds="3600" 缓存清除时间 默认是0 即永不过期
                       timeToLiveSeconds="0" 缓存存活时间 默认是0 即永不过期
                       overflowToDisk="true" 缓存对象达到最大数后,将其写入硬盘
                       maxElementsOnDisk="10000"  磁盘最大缓存数
                       diskPersistent="false" 磁盘持久化
                       diskExpiryThreadIntervalSeconds="120" 磁盘缓存的清理线程运行间隔
                       memoryStoreEvictionPolicy="FIFO" 缓存清空策略
                       FIFO 先进先出
                       LFU  less frequently used  最少使用
                       LRU  least recently used 最近最少使用
        />
        -->
    
    
        <cache name="testCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="3600"
               timeToLiveSeconds="0"
               overflowToDisk="false"
               statistics="true"
               memoryStoreEvictionPolicy="FIFO">
    
        </cache>
    </ehcache>
(3)在Mapper文件中配置cache标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
 
	<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
 
 	<!--public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName);  -->
 	<select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee">
 		select * from tbl_employee where last_name like #{lastName}
 	</select>
</mapper>
(4)测试类
@Test
public void testSecondLevelCache() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	SqlSession openSession2 = sqlSessionFactory.openSession();
	try{
 
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
		
		Employee emp01 = mapper.getEmpById(1);
		System.out.println(emp01);
		//关闭二级缓存才生效
		openSession.close();
		
		//第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
		Employee emp02 = mapper2.getEmpById(1);
		System.out.println(emp02);
		openSession2.close();
		
	}finally{
		
	}
}

参照缓存:若想在命名空间中共享相同的缓存配置和实例,可以使用cache-ref元素来引用另外一个缓存

  1. 缓存流程图在这里插入图片描述
    解读:

    (1)客户从数据库获取数据视为一次会话,抽象为sqlSession对象
    (2)一个Excutor包含增删改查的操作;
    (3)CachingExcutor是对Excutor的包装,此处相当于代理模式
    (4)当有会话时,先访问CachingExcutor对象,CachingExcutor先从二级缓存查找数据,如果有就直接返回;如果没有,就进入Excutor的一级缓存,如果还是没有就执行Excutor的增删改查返回结果,并将结果保存至缓存中,同一个sqlSession再次访问就可以从一级缓存中取了;
    (5)由于mybatis的缓存只用了map实现,所以mybatis允许缓存由第三方缓存来实现,并定义了cache接口,第三方只要实现该接口即可,和mybatis整合在一起后由mybatis在程序中进行调用;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值