MyBatis⑧缓存

MyBatis⑧缓存

 

13、缓存

13.1、简介

缓存(Cache)是存在内存中的临时数据。

  1. 为什么使用缓存?
    • 用户在查询数据时不用从磁盘上查询,而是从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题;
    • 减少和数据库的交互次数,减少系统开销,提高系统效率。
  2. 使用缓存
    • 经常查询且不经常改变的数据,可使用缓存;
    • 不经常查询或经常改变的数据,不使用缓存。

MyBatis包含一个强大的事务性查询缓存机制,易于配置和使用。

13.2、一级缓存

1、说明

一级缓存也叫会话缓存。

  • 默认情况下,只启用了本地的一级缓存;
  • 仅对一个会话中的数据进行缓存,即缓存只在一个SqlSession从获取到关闭这个区间有效;
  • 增删改操作会刷新缓存;

2、Mapper

/**
 * 根据ID获取用户
 * @param id 用户ID
 * @return 用户
 */
User getUserById(int id);
<select id="getUserById" resultType="user">
    select *
    from mybatis.user
    where id = #{id}
</select>

3、测试

进行以下3种测试:

  1. 同一会话中,查询相同数据;
  2. 同一会话中,查询不同数据;
  3. 不同会话中,查询相同数据。

同一会话中,查询相同数据

@Test
public void tesGetUserById() {
    // 获取SqlSession
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    // 获取Mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // 执行方法
    User user = mapper.getUserById(1);
    User user1 = mapper.getUserById(1);
    System.out.println("-----------");
    System.out.println(user);
    System.out.println("-----------");
    System.out.println(user1);
    System.out.println("-----------");
    System.out.println(user == user1);
    System.out.println("-----------");

    // 关闭连接
    sqlSession.close();
}

测试结果:在第一次查询的时候执行了SQL语句;第二次查询相同数据时,直接读取缓存。

同一会话中,查询不同数据

    // 执行方法
    User user = mapper.getUserById(1);
    User user1 = mapper.getUserById(2);
    System.out.println("-----------");
    System.out.println(user);
    System.out.println("-----------");
    System.out.println(user1);
    System.out.println("-----------");
    System.out.println(user == user1);
    System.out.println("-----------");

测试结果:在第一次查询的时候执行了SQL语句;第二次查询不同数据时,又执行了SQL语句。

不同会话中,查询相同数据。

@Test
public void tesGetUserById() {
    // 获取SqlSession会话
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    // 获取Mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // 执行方法
    User user = mapper.getUserById(1);

    System.out.println(user);

    // 关闭连接
    sqlSession.close();

    // --------------------------------

    // 获取另一个SqlSession会话
    SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
    // 获取Mapper
    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);

    // 执行方法
    User user1 = mapper1.getUserById(1);

    System.out.println(user1);

    // 关闭连接
    sqlSession1.close();
}

测试结果:

  • 在第一个会话中查询的时候执行了SQL语句;

  • 第二次会话中查询的时候没有读取缓存,又执行了SQL语句。

4、注意

  1. select 语句的结果将会被缓存。

  2. insert、update 和 delete 语句会刷新缓存,此时再查询之前查过的结果也需要重新执行SQL。

  3. 手动清理缓存

    sqlSession.clearCache();
    

13.3、二级缓存

1、说明

二级缓存也叫全局缓存。

  • 基于namespace级别的缓存,即一个Mapper中有效;
  • 需要在Mapper.xml中手动开启:<cache/>,就可以达成以下效果:
    • select语句的结果将会被缓存;
    • insertupdatedelete语句会刷新缓存;
    • 使用LRU算法(Least Recently Used)来清除不需要的缓存;
    • 缓存不会定时进行刷新(即没有刷新间隔)。
    • 缓存会保存1024 个列表或对象的引用 。
    • 缓存会被视为读/写缓存,即获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
  • 工作机制:
    • 一个会话中查询的数据,会放在一级缓存中;
    • 会话关闭,一级缓存失效,其中的数据被保存到二级缓存中;
    • 开启新的会话,先读取二级缓存,再读取当前会话的一级缓存;
    • 不同Mapper的数据存放在各自的缓存中。

2、使用

开启设置

全局缓存开启的默认值为true。为了提高可读性,如果要使用二级缓存,要显式地在核心配置文件中开启。

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

使用二级缓存

注意:开启二级缓存之前,涉及到的实体类要实现可序列化接口Serializable

在要使用二级缓存的Mapper.xml中使用cache标签。

<!-- 使用默认的二级缓存 -->
<cache/>

也可以自定义缓存配置

<!-- 使用自定义配置的二级缓存 -->
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

测试结果:

  1. 未开启二级缓存:

    • 两个会话的查询结果存储在各自的会话中,无法共享,都需要执行SQL语句。

测试:

  1. 第一条查询语句:先后读取二级缓存和一级缓存都没有相应数据,执行SQL并将结果保存到一级缓存。会话结束后,一级缓存失效,其内容保存到二级缓存。

  2. 第二条查询语句:读取二级缓存获取数据,无需执行SQL。

13.4、小结

  1. 一级缓存也叫会话缓存,在一个会话中有效;
  2. 二级缓存也叫全局缓存,在一个Mapper中有效;
  3. 默认情况下,一级缓存开启,二级缓存关闭;
  4. 当一次会话结束时,一级缓存失效,其中的数据保存到二级缓存中;
  5. 用户查数据的顺序:先读取二级缓存,再读取一级缓存,再访问数据库。
  6. 增删改操作都会刷新缓存。

13.4、Ehcache

可以更完善地自定义缓存配置。

  1. 导包

    <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.2.1</version>
    </dependency>
    
  2. 编写ehcache配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
    
        <diskStore path="./tmpdir/Tmp_EhCache"/>
    
        <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="259200"
                memoryStoreEvictionPolicy="LRU"/>
    
        <cache
                name="cloud_user"
                eternal="false"
                maxElementsInMemory="5000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="1800"
                memoryStoreEvictionPolicy="LRU"/>
    </ehcache>
    
  3. 使用Ehcache缓存

    <!-- 使用Ehcache缓存 -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
 
标签: MyBatis
 
posted @ 2022-02-24 22:58  扬帆起航$  阅读(48)  评论(0)    收藏  举报