2025/2/24 上午《尚硅谷》—— mybatis的二级缓存、相关配置、缓存查询顺序、EHcache——含实例演示代码

目录

一、mybatis的二级缓存

1、实例演示代码

Emp.java代码

CacheMapper.java代码

CacheMapper.xml代码

CacheMapperTest.java代码

2、输出结果

3、实例分析以及知识总结

1. 实例演示代码分析

2. 输出结果分析

3. MyBatis 二级缓存知识总结

二、mybatis的二级缓存相关配置和缓存查询顺序

1. cache 标签的属性配置

① eviction 属性:缓存回收策略

② flushInterval 属性:刷新间隔

③ size 属性:缓存对象的最大数量

④ readOnly 属性:缓存是否只读

2. 缓存查询顺序

3. 示例配置

4. 缓存查询顺序的代码示例

三、整合第三方缓存EHcache ——操作步骤

1、添加依赖

2、各 jar 包功能

3、创建 EHCache 配置文件 ehcache.xml

4、设置二级缓存的类型

5、加入 logback 日志

6、EHCache 配置文件说明

7、实例测试

7.1测试代码逻辑

7.2测试输出日志

7.2.1. 日志初始化

7.2.2. MyBatis 初始化

7.2.3. EHCache 初始化

7.2.4. 第一次查询

7.2.5. 第二次查询

7.2.6. 第三次查询

7.2.7、测试结果总结


一、mybatis的二级缓存

1、实例演示代码

Emp.java代码

//实体类_有参构造、无参构造、getter和Setter方法、tostring方法

package com.atguigu.mybatis.pojo;


import java.io.Serializable;

public class Emp implements Serializable {

    private Integer empId;

    private String empName;

    private Integer age;

    private String gender;

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }


    public Emp() {
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

CacheMapper.java代码

package com.atguigu.mybatis.mapper;

import com.atguigu.mybatis.pojo.Emp;
import org.apache.ibatis.annotations.Param;

public interface CacheMapper {
    /* *
     *
     *根据员工id查询员工信息
     * @param empId
     * @return com.atguigu.mybatis.pojo.Emp
     * @author yzh
     * @create 2025/2/24
     **/
    Emp getEmpById(@Param("empId") Integer empId);
    /* *
     *
     * 添加员工信息
     * @param emp
     * @return void
     * @author yzh
     * @create 2025/2/24
     **/
    void insertEmp(Emp emp);
}

CacheMapper.xml代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.CacheMapper">

    <cache />

    <!--Emp getEmpById(@Param("empId") Integer empId);-->
    <select id="getEmpById" resultType="Emp">
        select *
        from t_emp where emp_id = #{empId};
    </select>

    <!--void insertEmp(Emp emp);-->
    <insert id="insertEmp">
        insert into t_emp values (null,#{empName},#{age},#{gender},null)
    </insert>

</mapper>

CacheMapperTest.java代码

import com.atguigu.mybatis.mapper.CacheMapper;
import com.atguigu.mybatis.pojo.Emp;
import com.atguigu.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class CacheMapperTest {

    @Test
    public void testCache1() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession1 = sqlSessionFactory.openSession( true);
        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println(emp1);
        sqlSession1.close();
        SqlSession sqlSession2 = sqlSessionFactory.openSession( true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println(emp2);
        sqlSession2.close();
    }


}

2、输出结果

DEBUG 02-24 11:24:39,696 Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.0 (LoggingCache.java:60) 
DEBUG 02-24 11:24:39,859 ==>  Preparing: select * from t_emp where emp_id = ?; (BaseJdbcLogger.java:137) 
DEBUG 02-24 11:24:39,888 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137) 
DEBUG 02-24 11:24:39,912 <==      Total: 1 (BaseJdbcLogger.java:137) 
Emp{empId=1, empName='张三', age=20, gender='男'}
WARN  02-24 11:24:39,919 As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66 (SerialFilterChecker.java:46) 
DEBUG 02-24 11:24:39,925 Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.5 (LoggingCache.java:60) 
Emp{empId=1, empName='张三', age=20, gender='男'}

进程已结束,退出代码为 0

3、实例分析以及知识总结

1. 实例演示代码分析

        在提供的代码中,CacheMapperTest 类中的 testCache1 方法展示了 MyBatis 二级缓存的使用。以下是代码的执行流程:

  1. 第一次查询

    • 通过 SqlSessionFactory 创建 SqlSession1

    • 使用 SqlSession1 获取 CacheMapper 的实例 mapper1

    • 调用 mapper1.getEmpById(1) 查询员工信息。

    • 由于是第一次查询,缓存中没有数据,因此会从数据库中查询数据,并将查询结果存入二级缓存。

    • 查询结果打印为:Emp{empId=1, empName='张三', age=20, gender='男'}

  2. 第二次查询

    • 关闭 SqlSession1,此时一级缓存中的数据会被清空,但二级缓存中的数据仍然保留。

    • 通过 SqlSessionFactory 创建 SqlSession2

    • 使用 SqlSession2 获取 CacheMapper 的实例 mapper2

    • 调用 mapper2.getEmpById(1) 查询员工信息。

    • 由于二级缓存中已经存在该数据,因此直接从缓存中获取数据,而不需要再次访问数据库。

    • 查询结果打印为:Emp{empId=1, empName='张三', age=20, gender='男'}

2. 输出结果分析
  • 第一次查询

    • Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.0:表示缓存命中率为 0,即第一次查询时缓存中没有数据。

    • ==> Preparing: select * from t_emp where emp_id = ?;:表示 MyBatis 正在准备 SQL 查询。

    • ==> Parameters: 1(Integer):表示 SQL 查询的参数为 1

    • <== Total: 1:表示查询结果返回了 1 条记录。

    • Emp{empId=1, empName='张三', age=20, gender='男'}:查询结果。

  • 第二次查询

    • Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.5:表示缓存命中率为 50%,即第二次查询时从缓存中获取了数据。

    • Emp{empId=1, empName='张三', age=20, gender='男'}:查询结果。

3. MyBatis 二级缓存知识总结
  • 二级缓存的作用范围

    • MyBatis 的二级缓存是 SqlSessionFactory 级别的,即通过同一个 SqlSessionFactory 创建的多个 SqlSession 可以共享二级缓存。

  • 开启二级缓存的条件

    • 在 MyBatis 核心配置文件中,设置全局配置属性 cacheEnabled="true"(默认值为 true,通常不需要显式设置)。

    • 在映射文件中使用 <cache /> 标签开启二级缓存。

    • 二级缓存必须在 SqlSession 关闭或提交之后才会生效。

    • 查询的数据所转换的实体类必须实现 Serializable 接口。

  • 二级缓存失效的情况

    • 如果在两次查询之间执行了任意的增删改操作,MyBatis 会自动清空一级缓存和二级缓存,以确保数据的一致性。

  • 缓存命中率

    • 缓存命中率表示从缓存中获取数据的比例。在第一次查询时,缓存命中率为 0,因为数据是从数据库中查询的。在第二次查询时,缓存命中率为 50%,因为数据是从缓存中获取的。

二、mybatis的二级缓存相关配置和缓存查询顺序

1. cache 标签的属性配置

在 MyBatis 的 Mapper 配置文件中,可以通过 <cache /> 标签配置二级缓存的行为。以下是 <cache /> 标签的常用属性:

① eviction 属性:缓存回收策略
  • 默认值LRU

  • 可选值

    • LRU(Least Recently Used)- 最近最少使用:移除最长时间不被使用的对象。

    • FIFO(First In First Out)- 先进先出:按对象进入缓存的顺序来移除它们。

    • SOFT - 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    • WEAK - 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

② flushInterval 属性:刷新间隔
  • 单位:毫秒

  • 默认值:不设置(无刷新间隔)

  • 作用:设置缓存的自动刷新时间间隔。例如,设置为 60000 表示缓存每 60 秒刷新一次。

③ size 属性:缓存对象的最大数量
  • 类型:正整数

  • 默认值:无

  • 作用:设置缓存中最多可以存储的对象数量。如果缓存对象数量超过设置的值,会根据 eviction 策略移除对象。

④ readOnly 属性:缓存是否只读
  • 默认值false

  • 可选值

    • true:只读缓存。所有调用者会共享缓存对象的相同实例,性能较高,但缓存对象不能被修改。

    • false:读写缓存。每次返回缓存对象的拷贝(通过序列化),性能较低,但更安全。

2. 缓存查询顺序

MyBatis 的缓存查询顺序如下:

  1. 先查询二级缓存

    • 二级缓存是 SqlSessionFactory 级别的缓存,多个 SqlSession 可以共享。

    • 如果二级缓存中存在查询结果,则直接返回缓存数据,不再访问数据库。

  2. 如果二级缓存未命中,再查询一级缓存

    • 一级缓存是 SqlSession 级别的缓存,只在同一个 SqlSession 内有效。

    • 如果一级缓存中存在查询结果,则直接返回缓存数据。

  3. 如果一级缓存也未命中,则查询数据库

    • 如果一级缓存和二级缓存中都没有查询结果,则访问数据库获取数据。

    • 查询结果会先存入一级缓存,然后在 SqlSession 关闭或提交时,一级缓存中的数据会写入二级缓存。

3. 示例配置

以下是一个完整的 <cache /> 标签配置示例:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
  • eviction="FIFO":使用先进先出的缓存回收策略。

  • flushInterval="60000":设置缓存每 60 秒刷新一次。

  • size="512":缓存中最多存储 512 个对象。

  • readOnly="true":缓存为只读模式,性能较高但不允许修改缓存对象。

4. 缓存查询顺序的代码示例

以下是一个缓存查询顺序的代码示例:

@Test
public void testCacheOrder() throws IOException {
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

    // 第一次查询
    SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
    CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    Emp emp1 = mapper1.getEmpById(1); // 查询数据库,存入一级缓存
    System.out.println(emp1);
    sqlSession1.close(); // 一级缓存数据写入二级缓存

    // 第二次查询
    SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
    CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
    Emp emp2 = mapper2.getEmpById(1); // 从二级缓存中获取数据
    System.out.println(emp2);
    sqlSession2.close();

    // 第三次查询
    SqlSession sqlSession3 = sqlSessionFactory.openSession(true);
    CacheMapper mapper3 = sqlSession3.getMapper(CacheMapper.class);
    Emp emp3 = mapper3.getEmpById(1); // 从二级缓存中获取数据
    System.out.println(emp3);
    sqlSession3.close();
}

三、整合第三方缓存EHcache ——操作步骤

1、添加依赖

在 pom.xml 中添加以下依赖:

        <!-- Mybatis EHCache整合包 -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.1</version>
        </dependency>

        <!-- slf4j日志门面的一个具体实现 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
2、各 jar 包功能
Jar 包名称 作用
mybatis-ehcache MyBatis 和 EHCache 的整合包,用于将 EHCache 作为 MyBatis 的二级缓存实现。
ehcache EHCache 的核心包,提供缓存存储、缓存策略、缓存管理等功能。
slf4j-api SLF4J 日志门面包,提供统一的日志接口,支持多种日志实现。
logback-classic 支持 SLF4J 门面接口的一个具体实现,提供高性能的日志功能。

3、创建 EHCache 配置文件 ehcache.xml

创建 ehcache.xml 文件,配置示例如下:

<?xml version="1.0" encoding="utf-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="..//config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\atiguigu\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
4、设置二级缓存的类型

在 MyBatis 的 映射文件中,通过 <cache /> 标签指定使用 EHCache 作为二级缓存实现:

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
5、加入 logback 日志

在 logback.xml 中配置日志级别,以便查看 EHCache 的运行日志:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 日志输出的格式 -->
        <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%-5level] [%thread] %logger [%msg]%n</pattern>
        </encoder>
    </appender>

    <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT"/>
    </root>

    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.mybatis.mapper" level="DEBUG"/>
</configuration>
6、EHCache 配置文件说明

属性名

是否必须 作用
maxElementsInMemory 在内存中缓存的 element 的最大数目。
maxElementsOnDisk 在磁盘上缓存的 element 的最大数目。如果为 0,表示无穷大。
eternal 设定缓存中的 elements 是否永远不过期。如果为 true,缓存数据始终有效;如果为 false,则根据 timeToIdleSeconds 和 timeToLiveSeconds 判断过期。
overflowToDisk 设定当内存缓存溢出时,是否将过期的 element 缓存到磁盘上。
timeToIdleSeconds 当缓存在 EhCache 中的数据前后两次访问的时间超过 timeToIdleSeconds 时,这些数据会被删除。默认值为 0,表示可闲置时间无穷大。
timeToLiveSeconds 缓存 element 的有效生命期。默认值为 0,表示 element 存活时间无穷大。
diskSpoolBufferSizeMB DiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个 Cache 都应该有自己的一个缓冲区。
diskPersistent 在 VM 重启时是否启用磁盘保存 EhCache 中的数据。默认是 false
diskExpiryThreadIntervalSeconds 磁盘缓存清理线程的运行间隔。默认是 120 秒。每 120 秒,相应的线程会进行一次 EhCache 中数据的清理工作。
7、实例测试
7.1测试代码逻辑
@Test
public void testCacheOrder() throws IOException {
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

    // 第一次查询
    SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
    CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    Emp emp1 = mapper1.getEmpById(1); // 查询数据库,存入一级缓存
    System.out.println(emp1);
    sqlSession1.close(); // 一级缓存数据写入二级缓存

    // 第二次查询
    SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
    CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
    Emp emp2 = mapper2.getEmpById(1); // 从二级缓存中获取数据
    System.out.println(emp2);
    sqlSession2.close();

    // 第三次查询
    SqlSession sqlSession3 = sqlSessionFactory.openSession(true);
    CacheMapper mapper3 = sqlSession3.getMapper(CacheMapper.class);
    Emp emp3 = mapper3.getEmpById(1); // 从二级缓存中获取数据
    System.out.println(emp3);
    sqlSession3.close();
}
7.2测试输出日志

以下是测试执行时的日志输出,结合代码逻辑进行分析:


7.2.1. 日志初始化
12:47:31,695 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
12:47:31,696 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
12:47:31,696 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/C:/Users/%e6%9d%a8%e6%99%ba%e6%85%a7/Desktop/SSM/mybatis_cache/target/classes/logback.xml]
12:47:31,763 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
12:47:31,767 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
12:47:31,773 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
12:47:31,804 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to DEBUG
12:47:31,804 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
12:47:31,806 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.atguigu.mybatis.mapper] to DEBUG
12:47:31,806 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
12:47:31,807 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@43738a82 - Registering current configuration as safe fallback point
  • 说明

    • 日志系统初始化,加载 logback.xml 配置文件。

    • 配置了控制台日志输出,日志级别设置为 DEBUG


7.2.2. MyBatis 初始化
12:47:31.812 [DEBUG] [main] org.apache.ibatis.logging.LogFactory [Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.]
12:47:31.818 [DEBUG] [main] org.apache.ibatis.io.VFS [Class not found: org.jboss.vfs.VFS]
12:47:31.818 [DEBUG] [main] org.apache.ibatis.io.JBoss6VFS [JBoss 6 VFS API is not available in this environment.]
12:47:31.819 [DEBUG] [main] org.apache.ibatis.io.VFS [Class not found: org.jboss.vfs.VirtualFile]
12:47:31.819 [DEBUG] [main] org.apache.ibatis.io.VFS [VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.]
12:47:31.820 [DEBUG] [main] org.apache.ibatis.io.VFS [Using VFS adapter org.apache.ibatis.io.DefaultVFS]
  • 说明

    • MyBatis 初始化日志系统,使用 Slf4jImpl 作为日志适配器。

    • 检查并加载 VFS(虚拟文件系统)实现,最终使用默认的 DefaultVFS


7.2.3. EHCache 初始化
12:47:31.931 [DEBUG] [main] net.sf.ehcache.config.ConfigurationFactory [Configuring ehcache from ehcache.xml found in the classpath: file:/C:/Users/%e6%9d%a8%e6%99%ba%e6%85%a7/Desktop/SSM/mybatis_cache/target/classes/ehcache.xml]
12:47:31.931 [DEBUG] [main] net.sf.ehcache.config.ConfigurationFactory [Configuring ehcache from URL: file:/C:/Users/%e6%9d%a8%e6%99%ba%e6%85%a7/Desktop/SSM/mybatis_cache/target/classes/ehcache.xml]
12:47:31.934 [DEBUG] [main] net.sf.ehcache.config.ConfigurationFactory [Configuring ehcache from InputStream]
12:47:31.945 [DEBUG] [main] net.sf.ehcache.config.BeanHandler [Ignoring ehcache attribute xmlns:xsi]
12:47:31.945 [DEBUG] [main] net.sf.ehcache.config.BeanHandler [Ignoring ehcache attribute xsi:noNamespaceSchemaLocation]
12:47:31.946 [DEBUG] [main] net.sf.ehcache.config.DiskStoreConfiguration [Disk Store Path: D:\atiguigu\ehcache]
12:47:31.959 [DEBUG] [main] net.sf.ehcache.CacheManager [Creating new CacheManager with default config]
  • 说明

    • EHCache 从 ehcache.xml 文件中加载配置。

    • 配置磁盘缓存路径为 D:\atiguigu\ehcache

    • 创建 CacheManager 实例。


7.2.4. 第一次查询
12:47:32.393 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper [Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.0]
12:47:32.400 [DEBUG] [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction [Opening JDBC Connection]
12:47:32.591 [DEBUG] [main] org.apache.ibatis.datasource.pooled.PooledDataSource [Created connection 1396431506.]
12:47:32.594 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper.getEmpById [==>  Preparing: select * from t_emp where emp_id = ?;]
12:47:32.617 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper.getEmpById [==> Parameters: 1(Integer)]
12:47:32.638 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper.getEmpById [<==      Total: 1]
Emp{empId=1, empName='张三', age=20, gender='男'}
12:47:32.640 [DEBUG] [main] net.sf.ehcache.store.disk.Segment [put added 0 on heap]
12:47:32.642 [DEBUG] [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction [Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@533bda92]]
12:47:32.642 [DEBUG] [main] org.apache.ibatis.datasource.pooled.PooledDataSource [Returned connection 1396431506 to pool.]
  • 说明

    • 第一次查询时,缓存命中率为 0.0,表示缓存中没有数据。

    • 从数据库中查询数据,并将结果存入一级缓存。

    • 查询结果:Emp{empId=1, empName='张三', age=20, gender='男'}

    • 关闭 SqlSession1 时,一级缓存数据写入二级缓存。


7.2.5. 第二次查询
12:47:32.642 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper [Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.5]
Emp{empId=1, empName='张三', age=20, gender='男'}
  • 说明

    • 第二次查询时,缓存命中率为 0.5,表示从二级缓存中获取数据。

    • 查询结果与第一次相同,直接从缓存中返回。


7.2.6. 第三次查询
12:47:32.642 [DEBUG] [main] com.atguigu.mybatis.mapper.CacheMapper [Cache Hit Ratio [com.atguigu.mybatis.mapper.CacheMapper]: 0.6666666666666666]
Emp{empId=1, empName='张三', age=20, gender='男'}
  • 说明

    • 第三次查询时,缓存命中率为 0.6666666666666666,表示再次从二级缓存中获取数据。

    • 查询结果与之前相同,直接从缓存中返回。


7.2.7、测试结果总结
  • 缓存命中率

    • 第一次查询:0.0(未命中,从数据库查询)。

    • 第二次查询:0.5(命中,从二级缓存获取)。

    • 第三次查询:0.6666666666666666(命中,从二级缓存获取)。

  • 查询结果

    • 三次查询结果均为:Emp{empId=1, empName='张三', age=20, gender='男'}