MyBatis缓存学习笔记-尚硅谷

提示:这是MyBatis的第五篇,有兴趣的话可以看下:

一: MyBatis复习笔记整理

二: MyBatis的resultMap标签 自定义封装返回值类型

三: MyBatis动态SQL官方文档

四: MyBatis动态SQL学习笔记

文章目录

  • MyBatis缓存
    • 1、缓存简介
    • 2、一级缓存(本地缓存)
    • 3、二级缓存(全局缓存)
    • 4、缓存相关设置/属性
    • 5、缓存原理图
    • 6、整合第三方缓存


MyBatis缓存

1、缓存简介

将查询到的结果缓存到本地,再次查询时,从本地查询,无需再次发送SQL查询请求数据库。
MyBatis有两种缓存:

  • 一级缓存(本地缓存)
  • 二级缓存(全局缓存)

2、一级缓存(本地缓存)

一级缓存(本地缓存):
sqlSession会话级别的缓存。一级缓存是一直开启的;SqlSesison级别的一个Map
与数据库同一次会话期间查询到的数据会放在本地缓存中。
以后如果需要获取相同的数据,会直接从缓存中拿,没必要再去查询数据库。

	@Test
	public void testFirstLevelCache() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			Employee employee = mapper.getEmpById("1");
//			openSession.clearCache();
			Employee employee2 = mapper.getEmpById("1");
			System.out.println(employee);
			System.out.println(employee2);
			System.out.println(employee == employee2);
		} finally {
			openSession.close();
		}
	}

输出:

2021-07-12 20:10:24,480 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - ==>  Preparing: select * from tbl_Employee where id = ? 
2021-07-12 20:10:24,540 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - ==> Parameters: 1(String)
2021-07-12 20:10:24,570 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - <==      Total: 1
Employee [id=1, lastName=tom, email=[email protected], gender=1]
Employee [id=1, lastName=tom, email=[email protected], gender=1]
true

两次查询,只发送了一次SQL查询请求,并且2个Employee对象相等。

一级缓存失效情况:

  • 1、sqlSession不同。(一级缓存是会话级别的)
  • 2、sqlSession相同,查询条件不同。(当前一级缓存中还没有这个数据)
  • 3、sqlSession相同,两次查询之间执行了增删改操作。(这次操作可能对当前数据有影响)
  • 4、sqlSession相同,手动清除了一级缓存。(openSession.clearCache()清空缓存)

3、二级缓存(全局缓存)

二级缓存(全局缓存):
基于namespace级别的缓存:一个namespace对应一个二级缓存:

工作机制:

  • 1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
  • 2、如果会话关闭,一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的数据。
  • 3、sqlSession== 》EmployeeMapper== 》Employee
    DepartmentMapper== 》Department
    不同的namespace查出的数据会放在自己对应的缓存中。(map

效果:数据会从二级缓存中获取。

查出的数据会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
二级缓存的使用方法:

  • 1、开启全局二级缓存配置:
    <setting name="cacheEnabled" value="true"/>
    
  • 2、在mapper.xml中配置使用二级缓存:
    <cache><cache>
    
  • 3、JavaBean对象实现序列化接口
    public class Employee implements Serializable {
    

cache标签的相关属性设置:

<cache eviction="" flushInterval="" readOnly="" size="" type="">cache>

1、eviction缓存驱逐策略:

  • LRU— 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO— 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT— 软引用:移除基于垃圾回收站状态和软引用规则的对象。
  • WEAK— 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象。
  • 默认是LRU。移除最近最少使用的缓存对象。

2、flushInterval缓存刷新间隔:

  • 缓存多长时间情况一次。
  • 默认不清空。
  • 可以设置一个毫秒值。

3、readOnly是否只读:

  • true:只读:mybatis认为所有从缓存中获取数据的都是只读操作,不会修改数据。mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快。
  • false:非只读:mybatis觉得获取的数据可能会被修改。mybatis会利用序列化&反序列化的技术克隆一份新的数据给你。安全,但速度慢。
  • 默认为false非只读

4、size:缓存存放多少元素

5、type:指定自定义缓存的全类名。

  • 实现mybatisCache接口后,填写全类名

Java代码?拿来吧你:

@Test
	public void testSecondLevelCache() {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
//		获取2个sqlSession对象测试二级缓存
		SqlSession openSession2 = sqlSessionFactory.openSession();
		try {
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
			Employee employee = mapper.getEmpById("1");
//			一定要关闭sqlSession会话,才能将会话中的一级缓存转移到二级缓存中
			openSession.close();
			Employee employee2 = mapper2.getEmpById("1");
			System.out.println(employee);
			System.out.println(employee2);
			System.out.println(employee == employee2);
		} finally {
			openSession2.close();
		}
	}

输出结果,来拿:

2021-07-12 21:12:03,995 [main] DEBUG [com.atguigu.dao.EmployeeMapper] - Cache Hit Ratio [com.atguigu.dao.EmployeeMapper]: 0.0
2021-07-12 21:12:04,012 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - = => Preparing: select * from tbl_Employee where id = ?
2021-07-12 21:12:04,074 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - = => Parameters: 1(String)
2021-07-12 21:12:04,103 [main] DEBUG [com.atguigu.dao.EmployeeMapper.getEmpById] - <= = Total: 1
2021-07-12 21:12:04,121 [main] DEBUG [com.atguigu.dao.EmployeeMapper] - Cache Hit Ratio [com.atguigu.dao.EmployeeMapper]: 0.5
Employee [id=1, lastName=tom, [email protected], gender=1]
Employee [id=1, lastName=tom, [email protected], gender=1]
false

Cache Hit Ratio表示缓存命中率:第一次是0.0,因为没有缓存。第二次成功命中,2次命中一次,所以第二次为0.5,也就是50%

可以看到2个不同的sqlSession会话进行的2次查询,只发送了一个SQL语句的查询请求,说明二级缓存成功生效。

这里打印false是因为readOnly为默认值false,也就是mybatis认为可能数据会被修改,于是将数据序列化copy了一份。

4、缓存相关设置/属性

1、cacheEnabled="true": "false": 关闭(二级)缓存(一级缓存不受影响)

2、每个select标签都有useCache="true"

  • false:不使用缓存(一级缓存依然使用,二级缓存不使用)

3、每个增删改标签的:flushCache="true":(一级二级都会清除)

  • 增删改执行完成后就会清除缓存;
  • 测试:flushCache="true":一级缓存清空,二级缓存也清空
  • select查询标签默认flushCache="false"
  • 如果flushCache="true",那么每次查询之后都会清空缓存,缓存是没法用的。

4、sqlSession.clearCache();只是清除当前session的一级缓存;

5、localCacheScope:本地缓存作用域:

  • (一级缓存SESSION);当前会话的所有数据可在同SESSION会话中共享。
  • STATEMENT:可以禁用一级缓存。
    MyBatis缓存学习笔记-尚硅谷_第1张图片

5、缓存原理图

MyBatis缓存学习笔记-尚硅谷_第2张图片
先查询二级缓存,再查询一级缓存,最后查询数据库。

MyBatis缓存学习笔记-尚硅谷_第3张图片

6、整合第三方缓存

原理:MyBatis原生缓存底层就是一个Map实现的,比较简单。所以官方预留了Cache接口,只需要实现Cache接口,在配置中使用,即可提供给MyBatis调用,实现自定义缓存。

第三方缓存整合:

  • 1、导入第三方缓存及整合包依赖
		
		<dependency>
			<groupId>net.sf.ehcachegroupId>
			<artifactId>ehcache-coreartifactId>
			<version>2.6.8version>
		dependency>
		
		
		<dependency>
			<groupId>org.mybatis.cachesgroupId>
			<artifactId>mybatis-ehcacheartifactId>
			<version>1.2.1version>
		dependency>

		
		<dependency>
			<groupId>log4jgroupId>
			<artifactId>log4jartifactId>
			<version>1.2.14version>
		dependency>

		<dependency>
			<groupId>org.slf4jgroupId>
			<artifactId>slf4j-apiartifactId>
			<version>1.6.1version>
		dependency>

		<dependency>
			<groupId>org.slf4jgroupId>
			<artifactId>slf4j-log4j12artifactId>
			<version>1.6.1version>
		dependency>
  • 2、在mapper.xml中使用自定义缓存

    <cache type="org.mybatis.caches.ehcache.EhcacheCache">cache>
    

    cache标签中的type属性指定cache接口的实现类全类名即可。

  • 3、把ehcache.xml配置文件放到类路径

    
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
        
        <diskStore path="E:\work\demo\Tmp_EhCache"/>
        
        <defaultCache
                maxElementsInMemory="1"
                maxElementsOnDisk="10000"
                eternal="false"
                overflowToDisk="true"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="259200"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"/>
    
        
    ehcache>
    
  • 4、其他mapper.xml引用
    无需重复以上配置,只需要使用cache_ref标签的namespace属性指定上面已配置的命名空间即可。

    <cache-ref namespace="com.atguigu.dao.EmployeeMapper"/>
    

你可能感兴趣的:(java面试,基础复习,mybatis,java,mysql,sql,缓存)