当咱们大量执行重复的查询SQL语句的时候,会频繁的和数据库进行通讯,会增长查询时间等影响用户体验的问题,能够经过缓存,以下降网络流量,使网站加载速度更快.java
默认状况下,MyBatis只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。这也就是你们常说的MyBatis一级缓存,一级缓存的做用域是SqlSession。web
代码验证sql
//测试一级缓存 @Test public void testCache() throws IOException { //加载配置文件 InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml"); //获取工厂建造类 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取工厂对象 SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs); //获取SqlSession对象 SqlSession sqlSession = build.openSession(true); //获得代理的对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //根据名字查询 Student stu1 = mapper.findStudentByName("小花花"); Student stu2 = mapper.findStudentByName("小花花"); /* 这里相等,说明默认开启一级缓存,就是在同一个sqlSession域中有效,只要查询相同的语句,就是从一级缓存中获取 */ System.out.println("两次查询结果的学生对象是不是同一个:"+(stu1==stu2)); //关闭会话 sqlSession.close(); rs.close(); }
执行结果
由上面的执行结果得知
MyBatis是默认开启一级缓存的,做用域是同一个SqlSession,在同一个sqlSession中查询相同的sql语句,第一次查询后会将结果对象存放在一级缓存中,在后面查询相同的sql语句的时候会在一级缓存中去获取,不用在与数据库进行通讯,大大下降了查询速度.数据库
** 代码演示**缓存
//测试一级缓存 @Test public void testCache() throws IOException { //加载配置文件 InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml"); //获取工厂建造类 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取工厂对象 SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs); //获取SqlSession对象 SqlSession sqlSession = build.openSession(true); //获得代理的对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //根据名字查询 Student stu1 = mapper.findStudentByName("小花花"); Student stu2 = mapper.findStudentByName("小付"); System.out.println("两次查询结果的学生对象是不是同一个:"+(stu1==stu2)); //关闭会话 sqlSession.close(); rs.close(); }
控制台输出
安全
** 代码演示**网络
//测试一级缓存 @Test public void testCache() throws IOException { //加载配置文件 InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml"); //获取工厂建造类 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取工厂对象 SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs); //获取SqlSession对象 SqlSession sqlSession = build.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //获取SqlSession2对象 SqlSession sqlSession2 = build.openSession(true); StudentMapper mapper2 = sqlSession2.getMapper(StudentMapper.class); //根据名字查询 Student stu1 = mapper.findStudentByName("小花花"); Student stu2 = mapper2.findStudentByName("小花花"); System.out.println("两次查询结果的学生对象是不是同一个:"+(stu1==stu2)); //关闭会话 sqlSession.close(); rs.close(); }
控制台输出
session
代码演示app
//测试一级缓存 @Test public void testCache() throws IOException { //加载配置文件 InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml"); //获取工厂建造类 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取工厂对象 SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs); //获取SqlSession对象 SqlSession sqlSession = build.openSession(true); //获得代理的对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //根据名字查询 Student stu1 = mapper.findStudentByName("小花花"); //修改数据 stu1.setAge(18); //执行更新语句 mapper.updateStudent(stu1); //再次查询 Student stu2 = mapper.findStudentByName("小花花"); System.out.println("两次查询结果的学生对象是不是同一个:"+(stu1==stu2)); //关闭会话 sqlSession.close(); rs.close(); }
控制台输出
框架
MyBatis一级缓存的运行过程是这样的:执行SQL语句的过程当中,首次执行它时从数据库获取的全部数据会被存储在一段高速缓存中,从此执行这条语句时就会从高速缓存中读取结果,而不是再次查询数据库。MyBatis提供了默认下基于Java HashMap的缓存实现。
重点是要明白:MyBatis执行SQL语句以后,这条语句的执行结果被缓存,之后再执行这条语句的时候,会直接从缓存中拿结果,而不是再次执行SQL。可是一旦执行新增或更新或删除操做,缓存就会被清除。下面将分状况来验证一下。
很明显,以上各类状况验证了一级缓存的概念,在同个SqlSession中,查询语句相同的sql会被缓存,可是一旦执行新增或更新或删除操做,缓存就会被清除。
MyBatis 一级缓存最大的共享范围就是一个SqlSession内部,那么若是多个 SqlSession 须要共享缓存,则须要开启二级缓存.
当二级缓存开启后,同一个命名空间(namespace) 全部的操做语句,都影响着一个共同的 cache,也就是二级缓存被多个 SqlSession 共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
二级缓存开启条件
二级缓存默认是不开启的,须要手动开启二级缓存,实现二级缓存的时候,MyBatis要求返回的**POJO必须是可序列化的**。开启二级缓存的条件也是比较简单.
<!-- 通知 MyBatis 框架开启二级缓存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>
<!-- 表示DEPT表查询结果保存到二级缓存(共享缓存) cache 标签有多个属性,一块儿来看一些这些属性分别表明什么意义 eviction: 缓存回收策略,有这几种回收策略 LRU - 最近最少回收,移除最长时间不被使用的对象 FIFO - 先进先出,按照缓存进入的顺序来移除它们 SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象 WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象 默认是 LRU 最近最少回收策略 flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值 readOnly: 是否只读;true 只读,MyBatis 认为全部从缓存中获取数据的操做都是只读操做,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 以为数据可能会被修改 size : 缓存存放多少个元素 type: 指定自定义缓存的全类名(实现Cache 接口便可) blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。 我这里就使用默认的,不去设置参数 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
@Data //这个注解是lombok包下的,能够自动帮咱们添加getset方法等 public class Student implements Serializable { private Integer sid; private String name; private Integer age; }
//测试一级缓存 @Test public void testCache() throws IOException { //加载配置文件 InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml"); //获取工厂建造类 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取工厂对象 SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs); //获取SqlSession对象 SqlSession sqlSession = build.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //根据名字查询 Student stu1 = mapper.findStudentByName("小花花"); System.out.println("第一次查出的对象"+stu1); //关闭会话后,会将一级缓存的数据保存在二级缓存中 sqlSession.close(); //获取SqlSession2对象 SqlSession sqlSession2 = build.openSession(true); StudentMapper mapper2 = sqlSession2.getMapper(StudentMapper.class); //新的会话查询就会从二级缓存中获取数据 Student stu2 = mapper2.findStudentByName("小花花"); System.out.println("第二次查出的对象"+stu1); System.out.println("两次查询结果的学生对象是不是同一个:"+(stu1==stu2)); //关闭会话 sqlSession2.close(); rs.close(); }
控制台输出
图解查询语句执行流程