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();
    }
相关推荐
侠客行03173 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
老毛肚5 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
IT陈图图12 小时前
CANN生态数据引擎:minddata的缓存策略与性能调优
缓存·cann
啦啦啦_999915 小时前
Redis-2-queryFormat()方法
数据库·redis·缓存
独断万古他化16 小时前
【SSM开发实战:博客系统】(三)核心业务功能开发与安全加密实现
spring boot·spring·mybatis·博客系统·加密
forestsea17 小时前
深入理解Redisson RLocalCachedMap:本地缓存过期策略全解析
redis·缓存·redisson
啦啦啦_999919 小时前
Redis-0-业务逻辑
数据库·redis·缓存
自不量力的A同学19 小时前
Redisson 4.2.0 发布,官方推荐的 Redis 客户端
数据库·redis·缓存
fengxin_rou20 小时前
[Redis从零到精通|第四篇]:缓存穿透、雪崩、击穿
java·redis·缓存·mybatis·idea·多线程
fengxin_rou20 小时前
黑马点评实战篇|第二篇:商户查询缓存
缓存