【MybBatis高级篇】MyBatis 缓存机制

简介

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

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

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

一级缓存

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

一级缓存演示

同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中

pom

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath />
</parent>
<dependencies>
	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>druid-spring-boot-starter</artifactId>
	    <version>1.1.20</version>
	</dependency>
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	</dependency>
	<dependency>
	    <groupId>org.mybatis.spring.boot</groupId>
	    <artifactId>mybatis-spring-boot-starter</artifactId>
	    <version>2.1.1</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-test</artifactId>
	</dependency>
</dependencies>

yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/ry?serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver

#配置分页插件
pagehelper:
  helperDialect: mysql #设置数据库类型
  reasonable: true #开启合理化:页码<=0 查询第一页,页码>=总页数查询最后一页
  supportMethodsArguments: true #支持通过 Mapper 接口参数来传递分页参数

Mapper类

public interface SysConfigMapper {
    @Select("select * from sys_conifg")
    List<Map> selectList();
}

启动类

@MapperScan(basePackages = "cn.zysheep.mapper")
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

test类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Slf4j
public class SysConfigMapperTest {
    @Autowired
    SysConfigMapper sysConfigMapper;
    @Autowired
    SqlSessionFactory sqlSessionFactory;
     @Test
    public void testSelectList() {
        List<Map> maps1 = sysConfigMapper.selectList();
        List<Map> maps2 = sysConfigMapper.selectList();
        log.info("maps1: {}:", maps1);
        log.info("maps2: {}:", maps2);
    }
}

查询了两次,并没有走一级缓存,此时非常疑惑,不应该吖,mybatis不是默认开启一级缓存了吗?

在这里插入图片描述
原因: 因为使用sysConfigMapper代理对象查询是属于namespace级别,也就是二级缓存才能生效。后面使用二级缓存在解决该问题,那如何才能使用一级缓存呢,我们可以注入SqlSessionFactory 对象调用openSession()方法从而得到SqlSession手动执行sql语句

修改测试类代码

   @Test
    public void testExecuteSqlSession() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        SysConfigMapper mapper = sqlSession.getMapper(SysConfigMapper.class);
        List<Map> maps1 = mapper.selectList();

        List<Map> maps2 = mapper.selectList();
        log.info("maps1: {}:", maps1);
        log.info("maps2: {}:", maps2);
    }

在这里插入图片描述

测试一级缓存失效: 得到两个不同的SqlSession ,执行对应的查询语句,未命中索引。需要使用二级缓存可以解决这个问题

@Test
public void testExecuteSqlSession() {
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SysConfigMapper mapper1 = sqlSession1.getMapper(SysConfigMapper.class);
    List<Map> maps1 = mapper1.selectList();
    
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SysConfigMapper mapper2 = sqlSession2.getMapper(SysConfigMapper.class);
    List<Map> maps2 = mapper2.selectList();
    log.info("maps1: {}:", maps1);
    log.info("maps2: {}:", maps2);
}

二级缓存

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

使用步骤

原始SSM XML方式

1、全局配置文件mybatis-config.xml中开启二级缓存

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

2、需要使用二级缓存的映射文件****Mapper.xml处使用cache配置缓存

<cache />

3、注意:POJO需要实现Serializable接口

SpringBoot集成MyBatis注解方式

1、yml中开启二级缓存

mybatis:
  configuration:
    cache-enabled: true

2、Mapper层接口使用@CacheNamespace注解

@CacheNamespace(blocking = true)
public interface SysConfigMapper {

    @Select("select * from sys_config")
    List<Map> selectList();
}

在这里插入图片描述
基本上就是这样。这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

缓存相关属性

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

1、 eviction=“FIFO”:缓存回收策略。默认的是 LRU。

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

2、flushInterval:刷新间隔,单位毫秒。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
3、size:引用数目,正整数,代表缓存最多可以存储多少个对象,太大容易导致内存溢出
4、readOnly:只读,true/false

  • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
  • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

二级缓存演示

1、和一级缓存失效代码一样,只需要开启二级缓存,并且关闭 SqlSession

@Test
    public void testSecondLevelCache() {
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SysConfigMapper mapper1 = sqlSession1.getMapper(SysConfigMapper.class);
        List<Map> maps1 = mapper1.selectList();
		// 关闭sqlSession1 
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SysConfigMapper mapper2 = sqlSession2.getMapper(SysConfigMapper.class);
        List<Map> maps2 = mapper2.selectList();
        log.info("maps1: {}:", maps1);
        log.info("maps2: {}:", maps2);
        // 关闭sqlSession2
        sqlSession2.close();
    }

在这里插入图片描述
2、测试SpringBoot整合MyBatis基于接口SysConfigMapper注入的方式

@Test
public void testSysConfigMapper() {
    List<Map> maps1 = sysConfigMapper.selectList();
    List<Map> maps2 = sysConfigMapper.selectList();
    log.info("maps1: {}:", maps1);
    log.info("maps2: {}:", maps2);
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李熠漾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值