MyBatis基于XML的详细使用——缓存
目录
介绍
一级缓存的使用
特性
二级缓存
缓存的使用
缓存的属性
二级缓存的作用范围:
特性
介绍
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
<cache/>
当添加上该标签之后,会有如下效果:
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
在进行配置的时候还会分为一级缓存和二级缓存:
一级缓存:线程级别的缓存,是本地缓存,sqlSession级别的缓存
二级缓存:全局范围的缓存,不止局限于当前会话
一级缓存的使用
一级缓存是sqlsession级别的缓存,默认是存在的。在下面的案例中,大家发现我发送了两个相同的请求,但是sql语句仅仅执行了一次,那么就意味着第一次查询的时候已经将结果进行了缓存。
@Testpublic void test01() {
SqlSession sqlSession = sqlSessionFactory.openSession();try {EmpDao mapper = sqlSession.getMapper(EmpDao.class);List<Emp> list = mapper.selectAllEmp();for (Emp emp : list) {System.out.println(emp);}System.out.println("--------------------------------");List<Emp> list2 = mapper.selectAllEmp();for (Emp emp : list2) {System.out.println(emp);}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
在大部分的情况下一级缓存是可以的,但是有几种特殊的情况会造成一级缓存失效:
1. 一级缓存是sqlSession级别的缓存,如果在应用程序中开启了多个sqlsession,那么会造成缓存失效
@Testpublic void test02(){SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);List<Emp> list = mapper.selectAllEmp();for (Emp emp : list) {System.out.println(emp);}System.out.println("================================");SqlSession sqlSession2 = sqlSessionFactory.openSession();EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class);List<Emp> list2 = mapper2.selectAllEmp();for (Emp emp : list2) {System.out.println(emp);}sqlSession.close();sqlSession2.close();}
2. 在编写查询的sql语句的时候,一定要注意传递的参数,如果参数不一致,那么也不会缓存结果
3. 如果在发送过程中发生了数据的修改,那么结果就不会缓存
@Testpublic void test03(){SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);Emp empByEmpno = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno);System.out.println("================================");empByEmpno.setEname("zhangsan");int i = mapper.updateEmp(empByEmpno);System.out.println(i);System.out.println("================================");Emp empByEmpno1 = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno1);sqlSession.close();}
4. 在两次查询期间,手动去清空缓存,也会让缓存失效
@Testpublic void test03(){SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);Emp empByEmpno = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno);System.out.println("================================");System.out.println("手动清空缓存");sqlSession.clearCache();System.out.println("================================");Emp empByEmpno1 = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno1);sqlSession.close();}
特性
/*** 一级缓存* 特性:* 1.默认就开启了,也可以关闭一级缓存 localCacheScope=STATEMENT* 2.作用域:是基于sqlSession(默认),一次数据库操作会话。* 3.缓存默认实现类PerpetualCache ,使用map进行存储的* 4.查询完就会进行存储* 5.先从二级缓存中获取,再从一级缓存中获取* key==> sqlid+sql* 失效情况:* 1.不同的sqlSession会使一级缓存失效* 2.同一个SqlSession,但是查询语句不一样* 3.同一个SqlSession,查询语句一样,期间执行增删改操作* 4.同一个SqlSession,查询语句一样,执行手动清除缓存*/
二级缓存
二级缓存是全局作用域缓存,默认是不开启的,需要手动进行配置。
Mybatis提供二级缓存的接口以及实现,缓存实现的时候要求实体类实现Serializable接口,二级缓存在sqlSession关闭或提交之后才会生效。
缓存的使用
步骤:
1、全局配置文件中添加如下配置:
<setting name="cacheEnabled" value="true"/>
2、需要在使用二级缓存的映射文件出使用标签标注
3、实体类必须要实现Serializable接口
@Testpublic void test04(){SqlSession sqlSession = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class);Emp empByEmpno = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno);sqlSession.close();
Emp empByEmpno1 = mapper2.findEmpByEmpno(1111);System.out.println(empByEmpno1);sqlSession2.close();}
缓存的属性
eviction:表示缓存回收策略,默认是LRU
- LRU:最近最少使用的,移除最长时间不被使用的对象
- FIFO:先进先出,按照对象进入缓存的顺序来移除
- SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
- WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInternal:刷新间隔,单位毫秒
- 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size:引用数目,正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readonly:只读,true/false
- true:只读缓存,会给所有调用这返回缓存对象的相同实例,因此这些对象不能被修改。
- false:读写缓存,会返回缓存对象的拷贝(序列化实现),这种方式比较安全,默认值
//可以看到会去二级缓存中查找数据,而且二级缓存跟一级缓存中不会同时存在数据,因为二级缓存中的数据是在sqlsession 关闭之后才生效的
@Testpublic void test05(){SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);Emp empByEmpno = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno);sqlSession.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class);Emp empByEmpno2 = mapper2.findEmpByEmpno(1111);System.out.println(empByEmpno2);Emp empByEmpno3 = mapper2.findEmpByEmpno(1111);System.out.println(empByEmpno3);sqlSession2.close();}
缓存查询的顺序是先查询二级缓存再查询一级缓存
@Testpublic void test05(){SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao mapper = sqlSession.getMapper(EmpDao.class);Emp empByEmpno = mapper.findEmpByEmpno(1111);System.out.println(empByEmpno);sqlSession.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class);Emp empByEmpno2 = mapper2.findEmpByEmpno(1111);System.out.println(empByEmpno2);Emp empByEmpno3 = mapper2.findEmpByEmpno(1111);System.out.println(empByEmpno3);
Emp empByEmpno4 = mapper2.findEmpByEmpno(7369);System.out.println(empByEmpno4);Emp empByEmpno5 = mapper2.findEmpByEmpno(7369);System.out.println(empByEmpno5);sqlSession2.close();}
二级缓存的作用范围:
如果设置了全局的二级缓存配置,那么在使用的时候需要注意,在每一个单独的select语句中,可以设置将查询缓存关闭,以完成特殊的设置
1、在setting中设置,是配置二级缓存开启,一级缓存默认一直开启
<setting name="cacheEnabled" value="true"/>
2、select标签的useCache属性:
在每一个select的查询中可以设置当前查询是否要使用二级缓存,只对二级缓存有效
3、sql标签的flushCache属性
增删改操作默认值为true,sql执行之后会清空一级缓存和二级缓存,而查询操作默认是false
4、sqlSession.clearCache()
只是用来清楚一级缓存
特性
/*** 二级缓存:* 特性:* 1.默认开启了,没有实现* 2.作用域:基于全局范围,应用级别。* 3.缓存默认实现类PerpetualCache ,使用map进行存储的但是二级缓存根据不同的mapper命名空间多包了一层map* : org.apache.ibatis.session.Configuration#caches key:mapper命名空间 value:erpetualCache.map* * key==> sqlid+sql* 4.事务提交的时候(sqlSession关闭)* 5.先从二级缓存中获取,再从一级缓存中获取* 实现:* 1.开启二级缓存<setting name="cacheEnabled" value="true"/>* 2.在需要使用到二级缓存的映射文件中加入<cache></cache>,基于Mapper映射文件来实现缓存的,基于Mapper映射文件的命名空间来存储的* 3.在需要使用到二级缓存的javaBean中实现序列化接口implements Serializable* 配置成功就会出现缓存命中率 同一个sqlId: 从缓存中拿出的次数/查询总次数** 失效:* 1.同一个命名空间进行了增删改的操作,会导致二级缓存失效* 但是如果不想失效:可以将SQL的flushCache 这是为false,但是要慎重设置,因为会造成数据脏读问题,除非你能保证查询的数据永远不会执行增删改* 2.让查询不缓存数据到二级缓存中useCache="false"* 3.如果希望其他mapper映射文件的命名空间执行了增删改清空另外的命名空间就可以设置:* <cache-ref namespace="cn.tulingxueyuan.mapper.DeptMapper"/>**/
MyBatis基于XML的详细使用——缓存相关推荐
- Mybatis-06【MyBatis基于XML的详细使用——缓存】
MyBatis基于XML的详细使用--缓存1.介绍2.一级缓存的使用3.二级缓存1. 缓存的使用2. 缓存的属性3. 二级缓存的作用范围4. 整合第三方缓存 1.介绍 MyBatis 内置了一个强大的 ...
- mybatis笔记-04【MyBatis基于XML的详细使用——高级结果映射】
1.联合查询 emp.java 1 package cn.tulingxueyuan.pojo; 2 3 import java.time.LocalDate; 4 5 /*** 6 * @Autho ...
- mybatis mapper.xml 文件共用_MyBatis 缓存原来是这么一回事儿!| 原力计划
作者 | Lw中责编 | 夕颜出品 | CSDN(ID:CSDNnews) 什么是缓存? 缓存就是存储数据的一个地方(称作:Cache),当程序要读取数据时,会首先从缓存中获取,有则直接返回,否则从其 ...
- Mybatis基于XML配置SQL映射器(二)
Mybatis之XML注解 之前已经讲到通过 mybatis-generator 生成mapper映射接口和相关的映射配置文件: 下面我们将详细的讲解具体内容 首先我们新建映射接口文档 sysUse ...
- mybatis(二)xml配置文件详细说明
目录 文章目录 mybatis(二)xml配置方式详细说明 2.1.使用properties配置属性 2.1.1.引入外部properties文件或在properties标签内定义属性 2.1.1.1 ...
- MyBatis基于XML的使用——缓存
1.介绍 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地 配置和定制. 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进. 默认情况下,只启用 ...
- Mybatis基于XML配置SQL映射器(一)
Durid和Mybatis开发环境搭建 SpringBoot搭建基于Spring+SpringMvc+Mybatis的REST服务(http://www.cnblogs.com/nbfujx/p/76 ...
- spring整合mybatis基于xml配置
数据库 /* Navicat MySQL Data Transfer Source Server : mysql Source Server Version : 50549 Sourc ...
- mybatis基于XML(二)
1.创建MySQL数据库:mybatisDemo和表:user 2.建立一个Java工程,并导入相应的jar包,具体目录如下 3.在 MyBatisTest 工程中添加数据库配置文件 mybatis- ...
最新文章
- anago 围棋_跳进我的碗里—关于中惒围棋加盟那些事
- 关于leetcode第K个最大元素的几种解法
- java集合系列之18 spring boot程序员的必修课
- 百度App Objective-C/Swift 组件化混编之路(一)
- at指令 和c语言,学渣求指教,如何识别字符串中的AT命令并逐个输出,求程序!!!...
- MySQL 1064 错误
- 用Java刷OJ超时怎么办?原因分析及解决方式
- mysql端口被占用_MySQL重启端口被占用处理
- Codeforces Round #359 div2
- 《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.1.1 确定参数...
- 认识队列技术中的硬件队列和软件队列及如何改变硬件队列长度
- c/c++ 时间函数总结 linux
- java 堆_Java 对象都是在堆上分配内存吗?
- 浅析几种常见RAID模式。DVI接口种类!以及18针24针的区别!
- 小米抢购神器-开放源码
- 机器学习笔记——从手写数字识别开始
- 使用hibernate映射oracle两个表空间的表,Hibernate每个具体类一张表映射(使用XML)
- 20230304 CF855 div3 vp
- 移动通信第六章,多址技术
- java se中的se指什么,什么是Java SE?