MyBatis--缓存机制

MyBatis--缓存机制

六、MyBatis 缓存机制

MyBatis 包含一个非常强大的查询缓存特性,它可以非 常方便地配置和定制。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存。
一级缓存和二级缓存。

  • 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
  • 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

6.1、一级缓存

一级缓存(local cache), 即本地缓存, 作用域默认 为sqlSession。当 Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。
本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域。
在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置。

一级缓存演示&失效情况
同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中。
key:hashCode+查询的SqlId+编写的sql查询语句+参数。
一级缓存失效的四种情况:

1、不同的SqlSession对应不同的一级缓存 
2、同一个SqlSession但是查询条件不同 
3、同一个SqlSession两次查询期间执行了任何一次增 删改操作 
4、同一个SqlSession两次查询期间手动清空了缓存


缓存数据:

@Test
public void testFirstLevelCache() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    try{
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee emp01 = mapper.getEmpById(1);
        System.out.println(emp01);
        
        //xxxxx
        //1、sqlSession不同。
        //SqlSession openSession2 = sqlSessionFactory.openSession();
        //EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
        
        //2、sqlSession相同,查询条件不同
        
        //3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
        //mapper.addEmp(new Employee(null, "testCache", "cache", "1"));
        //System.out.println("数据添加成功");
        
        //4、sqlSession相同,手动清除了一级缓存(缓存清空)
        //openSession.clearCache();
        
        Employee emp02 = mapper.getEmpById(1);
        //Employee emp03 = mapper.getEmpById(3);
        System.out.println(emp02);
        //System.out.println(emp03);
        System.out.println(emp01==emp02);
        
        //openSession2.close();
    }finally{
        openSession.close();
    }
}

6.2、二级缓存

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

6.2.1、使用步骤:

1、全局配置文件中开启二级缓存

<setting name= "cacheEnabled" value="true"/> 

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <setting name="jdbcTypeForNull" value="NULL"/>
    <!--显式的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

2、需要使用二级缓存的映射文件处使用cache配置缓存
3、注意:POJO需要实现Serializable接口。

6.2.2、缓存相关属性:

  • eviction:缓存的回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
  • flushInterval:刷新间隔,单位毫秒
    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size:引用数目,正整数
    代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly:只读,true/false
    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。
    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是false。
  • type="":指定自定义缓存的全类名;实现Cache接口即可;

6.2.3、缓存相关设置

  • 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。

6.2.4、测试代码

@Test
public void testSecondLevelCache() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession openSession = sqlSessionFactory.openSession();
    SqlSession openSession2 = sqlSessionFactory.openSession();
    try{
        //1、
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
        
        Employee emp01 = mapper.getEmpById(1);
        System.out.println(emp01);
        openSession.close();
        
        //第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
//      mapper2.addEmp(new Employee(null, "aaa", "nnn", "0")); //增删改清除缓存
        Employee emp02 = mapper2.getEmpById(1);
        System.out.println(emp02);
        openSession2.close();
        
    }finally{
        
    }
}

如下:

6.3、第三方缓存整合

EhCache 是一个纯Java的进程内缓存框架,具有快速、精 干等特点,是Hibernate中默认的CacheProvider。
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配置文件
  • 3、配置cache标签(在映射文件中)
<cache type= "org.mybatis.caches.ehcache.EhcacheCache"></cache> 

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

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
    <cache-ref namespace="com.atguigu.mybatis.dao.EmployeeMapper"/>

访问过程:

评论

暂无

添加新评论