Mybatis——缓存

1. 缓存的概念

缓存(Cache)是一种用于存储临时数据的机制,其核心目的是通过保存频繁访问或计算成本高的数据副本,来提升系统性能和响应速度。缓存通常位于数据访问路径的中间层,介于数据消费者(如应用程序)和数据源(如数据库、远程API)之间。

主要特点:

  • 高速存取:缓存通常使用内存等高速存储介质,相比磁盘或网络I/O可提供更快的访问速度

  • 数据暂存:缓存数据通常是原始数据的副本,具有临时性特征

  • 智能淘汰:当缓存空间不足时,会通过LRU(最近最少使用)、FIFO等算法自动淘汰旧数据

常见应用场景:

  1. CPU缓存:现代处理器中的L1/L2/L3缓存,用于减少访问主内存的延迟

  2. Web缓存:浏览器缓存静态资源(如图片、CSS),CDN缓存网站内容

  3. 数据库缓存:如Redis缓存查询结果,MySQL的查询缓存

  4. 应用缓存:Memcached缓存计算结果,减轻后端负担

典型工作流程示例:

  1. 应用首先检查缓存中是否存在所需数据

  2. 若存在(缓存命中),则直接使用缓存数据

  3. 若不存在(缓存未命中),则从原始数据源获取

  4. 将获取的数据存入缓存供后续使用

  5. 根据预设策略定期更新或失效缓存数据

缓存的关键指标:

  • 命中率:成功从缓存获取数据的请求比例

  • 延迟:从缓存获取数据所需时间

  • 一致性:缓存数据与源数据的同步程度

  • 吞吐量:单位时间内可处理的缓存请求数

注意事项:

  • 需要考虑缓存雪崩、缓存穿透等问题

  • 需要平衡缓存一致性与性能的关系

  • 大数据量场景下需注意内存管理

2. Mybatis一级缓存

Mybatis 一级缓存是 SqlSession 级别的缓存,当同一个 SqlSession 执行相同的 SQL 语句时,Mybatis 会优先从缓存中获取结果,而不是直接查询数据库。

核心特性:

  • 作用范围 :一级缓存的生命周期与SqlSession相同,只在单个SqlSession内有效

  • 自动启用:一级缓存默认开启,无需额外配置

  • 缓存策略:基于PerpetualCache实现,底层是Map集合存储缓存数据,Map<k,v> k指SQL语句 v指查询出来的值

java 复制代码
    /**
     * 证明一级缓存的存在
     * MyBatis的一级缓存也是SqlSession的缓存     factory工厂对象 -> sqlSession对象 -> mapper代理对象
     * 不同的SqlSession之间的缓存不能互相访问
     * 一级缓存底层是Map集合
     * Map<k,v> k指SQL语句 v指查询出来的值
     */
    @Test
    public void run1() throws IOException {
        //加载配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //通过流创建工厂对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取到sqlsession对象,没有设置事务的方式,默认手动提交
        SqlSession sqlSession = factory.openSession();
        //获取代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用方法 通过主键查询
        //先查询一级缓存,没有数据。会查数据库,都会有SQL语句,把查询出的数据存储到一级缓存中
        User user = mapper.findById(1);
        //打印地址
        System.out.println(user);

        System.out.println("==================================");

        //变式1 若执行手动清空缓存,则两条sql语句
        //sqlSession.clearCache();

        //变式2 日志会有一条sql语句,因为两个代理对象都是一个sqlSession对象
        //UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
        //User user1=mapper1.findById(1);


        //变式3 两个sqlSession对象,缓存不能互相访问,则会有两条sql语句
        //SqlSession sqlSession1 = factory.openSession();
        //UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);


        //再查询一次
        //同一个mapper代理对象,先查询一级缓存,存在数据。从缓存中把数据返回,就没有SQL语句
        User user1=mapper.findById(1);
        //这样两个user对象地址一样
        System.out.println(user1);

        sqlSession.close();
        inputStream.close();
    }

3. Mybatis二级缓存

MyBatis二级缓存是跨SqlSession的缓存,其生命周期与整个应用相同。与一级缓存(SqlSession级别)不同,二级缓存可以实现多个SqlSession共享数据。

在全局xml中配置

XML 复制代码
    <settings>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 将积极加载改为消极加载及按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

在Xxxmapper.xml中配置

XML 复制代码
<!--开启二级缓存使用-->
<cache/>
java 复制代码
    /**
     * 二级缓存是工厂factory的缓存       factory工厂对象 -> sqlSession对象 -> mapper代理对象
     * 证明二级缓存 (二级缓存的使用对象地址不同 但是也是从缓存加载
     * 原因是二级缓存存储的是零散数据  组装出来的对象)
     * 演示二级缓存
     */
    @Test
    public void run2() throws IOException {
        //加载配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //通过流创建工厂对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取到sqlsession对象,没有设置事务的方式,默认手动提交
        SqlSession sqlSession = factory.openSession();
        //获取代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用方法 通过主键查询
        //先查询一级缓存,没有数据。会查数据库,都会有SQL语句,把查询出的数据存储到一级缓存中
        User user = mapper.findById(1);
        //打印地址
        System.out.println(user);
        System.out.println("=====================");
        //手动清空缓存
        sqlSession.clearCache();
        sqlSession.commit();
        //关闭session
        sqlSession.close();

        //同一个factory工厂的不同sqlSession对象,对二级缓存没影响
        SqlSession sqlSession1=factory.openSession();


        //变式1 创新一个新的工厂,让sqlSession1走新工厂,缓存不能互相访问,则会有两条sql语句
        //注意,创建新的工厂需重新获取流
        //InputStream inputStream1 = Resources.getResourceAsStream("SqlMapConfig.xml");
        //SqlSessionFactory factory1 = new SqlSessionFactoryBuilder().build(inputStream1);
        //SqlSession sqlSession1=factory1.openSession();


        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        //再查询一次
        //先查询一级缓存,存在数据。从缓存中把数据返回,就没有SQL语句
        User user1=mapper1.findById(1);
        //这样两个user对象地址一样
        System.out.println(user1);

        sqlSession1.close();
        inputStream.close();
    }
相关推荐
s***11701 小时前
一、安装Redis(win11环境下)
数据库·redis·缓存
s***P9823 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
还是鼠鼠3 小时前
Redisson实现的分布式锁能解决主从一致性的问题吗?
java·数据库·redis·分布式·缓存·面试·redisson
2301_795167204 小时前
Python 高手编程系列八:缓存
开发语言·python·缓存
5***V9335 小时前
SQL 基础 BETWEEN 的常见用法
数据库·sql·mybatis
Java水解6 小时前
MyBatis 源码深度解析:从 Spring Boot 实战到底层原理
后端·mybatis
lunzi_fly8 小时前
【源码解读之 Mybatis】【核心篇】-- 第8篇:ResultSetHandler结果集处理
mybatis
j***82709 小时前
Mybatis控制台打印SQL执行信息(执行方法、执行SQL、执行时间)
数据库·sql·mybatis
m***923811 小时前
Window下Redis的安装和部署详细图文教程(Redis的安装和可视化工具的使用)
数据库·redis·缓存