Spring Boot 项目集成 MyBatis 一级缓存与二级缓存完整指南

Spring Boot 项目集成 MyBatis 一级缓存与二级缓存完整指南

在实际开发中,频繁访问数据库会导致性能下降。MyBatis 提供的 两级缓存机制 能够显著减少数据库访问,提高系统性能。本文将详细讲解如何在 Spring Boot 项目中使用 MyBatis 的一级缓存和二级缓存,并展示其使用效果和注意事项。


一、MyBatis 缓存机制概述

MyBatis 内置两级缓存:

  1. 一级缓存 (Local Cache)
  2. 范围:SqlSession 级别
  3. 默认状态:开启,无法关闭
  4. 生命周期:与 SqlSession 一样,SqlSession 执行 flush/commit/close 时清空
  5. 特点:同一 SqlSession 内,执行一样的查询 SQL,只访问数据库一次,后续直接从缓存读取
  6. 二级缓存 (Global Cache)
  7. 范围:Mapper (Namespace) 级别
  8. 默认状态:关闭,需要手动开启
  9. 生命周期:随应用程序存在,多个 SqlSession 可共享
  10. 特点:当 SqlSession 关闭或提交后,查询结果才会被存入二级缓存,供其他 SqlSession 使用

二、一级缓存(默认开启)

一级缓存无需额外配置,直接使用。

示例

@Mapper
public interface UserMapper {
    User selectUserById(Long id);
    void updateUserName(Long id, String name);
}

测试:

@SpringBootTest
public class MybatisCacheTest {
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Test
    public void testFirstLevelCache() {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);

            User u1 = mapper.selectUserById(1L); // 走数据库
            User u2 = mapper.selectUserById(1L); // 命中一级缓存,不查库

            System.out.println(u1 == u2); // true,同一个对象
        }
    }

    @Test
    public void testFirstLevelCacheInvalidation() {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);

            mapper.selectUserById(1L);
            mapper.updateUserName(1L, "NewName"); // 更新操作清空缓存
            mapper.selectUserById(1L); // 再次查库
        }
    }
}

✅ 总结:

  • 一级缓存只在同一 SqlSession 有效
  • 增删改操作会清空缓存,避免脏数据

三、二级缓存(手动开启)

1. 开启配置

application.yml

mybatis:
  configuration:
    cache-enabled: true

Mapper 注解方式:

@Mapper
@CacheNamespace // 启用二级缓存
public interface UserMapper {
    User selectUserById(Long id);
}

或 XML 方式:

<mapper namespace="com.example.mapper.UserMapper">
    <cache/>
    <select id="selectUserById" resultType="User">
        select * from user where id = #{id}
    </select>
</mapper>

2. 实体类需实现序列化

@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String name;
    private Integer age;
}

3. 验证二级缓存

@Test
public void testSecondLevelCache() {
    try (SqlSession s1 = sqlSessionFactory.openSession();
         SqlSession s2 = sqlSessionFactory.openSession()) {

        UserMapper m1 = s1.getMapper(UserMapper.class);
        UserMapper m2 = s2.getMapper(UserMapper.class);

        User u1 = m1.selectUserById(1L); // 查询数据库
        s1.close(); // 关闭 session,数据写入二级缓存

        User u2 = m2.selectUserById(1L); // 命中二级缓存,不查库

        System.out.println(u1 == u2); // false,但数据一样
    }
}

✅ 总结:

  • 二级缓存数据在 SqlSession commit/close 后才写入
  • 增删改会清空对应 Mapper 的二级缓存

四、使用第三方缓存(Ehcache 示例)

MyBatis 自带的二级缓存功能简单,生产中一般用 EhcacheRedis 等替代。

1. 添加依赖

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.9.2</version>
</dependency>

2. 配置 ehcache.xml

<ehcache updateCheck="false">
    <diskStore path="java.io.tmpdir/ehcache"/>

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="false"/>

    <cache name="com.example.mapper.UserMapper"
           maxElementsInMemory="1000"
           eternal="false"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           overflowToDisk="false"/>
</ehcache>

3. 修改 Mapper

@Mapper
@CacheNamespace(implementation = org.mybatis.caches.ehcache.EhcacheCache.class)
public interface UserMapper {
    User selectUserById(Long id);
}

五、注意事项

  1. 脏数据风险:多个 Mapper 操作同一表时,缓存同步不必定及时
  2. 事务性:只有 commit/close 后,二级缓存才生效
  3. 适用场景:读多写少(字典表、配置表)适合开启二级缓存,写多读少的业务表不提议使用
  4. 分布式环境:二级缓存最好结合 Redis 等分布式缓存方案

六、一级缓存 vs 二级缓存对比

特性

一级缓存

二级缓存

作用范围

SqlSession 内部

Mapper (Namespace) 级别,跨 SqlSession

默认状态

开启

关闭

生命周期

随 SqlSession 销毁

随应用存在

失效条件

增删改 / commit / close

对应 Mapper 执行增删改

共享性

不能共享

可共享


七、总结

  • 一级缓存:默认开启,无需配置
  • 二级缓存:需显式开启,适合读多写少的场景
  • 第三方缓存:推荐使用 Ehcache 或 Redis 提升可扩展性

Spring Boot 项目集成 MyBatis 一级缓存与二级缓存完整指南

© 版权声明

相关文章

2 条评论

  • 头像
    飘鹿凌 读者

    好棒👏

    无记录
    回复
  • 头像
    不爱吃香菜的小hh 投稿者

    收藏了,感谢分享

    无记录
    回复