Mybatis缓存

目录儿

  • 一级缓存
    • 测试代码
    • 溯源:一级缓存在哪儿?
  • 二级缓存
    • 开启二级缓存步骤
    • 测试代码:

一级缓存

mybatis默认开启一级缓存,是sqlSession级别的缓存,在操作数据库的时候,都要构建一个sqlSession对象,其对象内部有一个map接口,用来缓存结果数据。

在同一个sqlSession当中,执行完全一致的查询语句,会首先查询一级缓存,如果找到有对应的查询结果数据,则从缓存中读取数据,如果找不到,则去磁盘查DB,走磁盘IO,查到数据后,把结果数据写入一级缓存,返回给用户。

如果在两次查询之间执行了DML操作(Data Manipulation Language),则sqlSession会清空一级缓存,防止脏数据。

测试代码

用两次查询到的对象相同来证明第二次查询的对象是第一次查询结果

@Test
public void test01(){TeacherMapper dao sqlSession.getMapper(TeacherMapper.class);//第一次读取,会发行sg1Teacher teacher dao.selectone(tno:"1001");System.out.println(teacher);System.0Ut.println("=============================");//第二此读取数据,不会发行sqL,直接从缓存中获取数据Teacher teacher1 dao.selectone(tno:"1001");System.out.println(teacher1);System.out.println(teacher==teacher1);
}

当两次查询中间增加一个DML操作:

@Test
public void test01(){TeacherMapper dao sqlSession.getMapper(TeacherMapper.class);//第一次读取,会发行sg1Teacher teacher dao.selectone(tno:"1001");System.out.println(teacher);System.0Ut.println("=============================");Teacher temp = new Teacher();temp.setTno("3001");temp.setTname("临时代课老师");dao.insertone(temp);sqlSession.commit();  // 插入操作会清空缓存System.0Ut.println("=============================");//第二此读取数据,不会发行sqL,直接从缓存中获取数据Teacher teacher1 dao.selectone(tno:"1001");System.out.println(teacher1);System.out.println(teacher==teacher1);
}

因此第两次查询到的对象不是同一个。

溯源:一级缓存在哪儿?


其中可以看到默认开启了缓存

二级缓存

因为一级缓存是在同一个sqlSession中才有效,但很多场景是多个sqlSession并发工作,二级缓存就是为了解决这个问题。

二级缓存是基于Mappernamespace)级别的缓存,对于同一个Mapper文件不同sqlSession对象,可以共享缓存中的内容。

二级缓存默认是不开启的,需要手动开启。

只有当一级缓存,SqlSession对象使用完毕后能够关闭时,二级缓存才能正常命中,否则将会出现缓存命中为零的现象。

开启二级缓存步骤

  1. application配置文件中指定mybatisxml 配置文件路径

  2. mybatisxml 配置文件路径,设置开启缓存:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!-- 全局参数 --><settings><!-- 使全局的映射器启用或禁用缓存 --><setting name="cacheEnabled"             value="true"   /><!-- 允许JDBC 支持自动生成主键 --><setting name="useGeneratedKeys"         value="true"   /><!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 --><setting name="defaultExecutorType"      value="SIMPLE" /><!-- 指定 MyBatis 所用日志的具体实现 --><setting name="logImpl"                  value="SLF4J"  /><!-- 使用驼峰命名法转换字段 --><!-- <setting name="mapUnderscoreToCamelCase" value="true"/> --></settings>	
    </configuration>
    
  3. 为具体的Mapper映射文件的命名空间进行二级缓存的具体配置。

    <!-- 配置当前命名空间下mapper的缓存 -->
    <cache type="org.apache.ibatis.cache.impl.PerpetualCache"eviction= "LRU" flushInterval= "100000" readOnly= "true" size= "1024"/>
    

    也可以简单配置使用默认参数

    <cache/>
    
  4. 使缓存对象的实体类实现序列化接口(Serializable
    由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,实现序列化接口的目是二级缓存可能会使用硬盘临时存储,所以要实现序列化接口保证对象能够被序列化和反序列化。

  5. 为具体sql语句设置缓存开关(不设置默认允许/打开缓存)
    开启缓存的弊端是数据没有实时性,当数据库中的数据一旦修改,查询的数据还是缓存中的数据没有实时性,对于某些需要实时性显示数据的接口我们可以设置 useCache="false" ,设置该属性后,该接口每次查询出来都是去执行sql查询出实时性数据。如:

  6. 为具体sql语句设置缓存刷新开关(不设置默认刷新缓存)
    清空缓存,一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。但是如果你不想刷新缓存只需要这么做:

测试代码:

@Test
public void test01(){TeacherMapper mapper1 = sqlSession.getMapper(TeacherMapper.class);//第一次读取,会发行sg1Teacher teacher = mapper1.selectone(tno:"1001");System.out.println(teacher);System.0Ut.println("=============================");sqlSession.commit(); // 需要commit后才会把结果放入二级缓存SqlSession session = sqlSessionFactory.openSession(); // 新开一个sessionTeacherMapper mapper2 = sqlSession.getMapper(TeacherMapper.class);//第二此读取数据,不会发行sqL,直接从缓存中获取数据Teacher teacher1 = mapper2.selectone(tno:"1001");System.out.println(teacher1);System.out.println(teacher == teacher1);
}

本文链接:https://my.lmcjl.com/post/14548.html

展开阅读全文

4 评论

留下您的评论.