MyBatis的缓存机制

总结

MyBatis采用两级缓存机制:
1. 一级缓存:SqlSession级别,默认开启,同一会话中相同查询直接复用缓存结果,执行更新操作或关闭会话时自动清空。
2. 二级缓存:Mapper级别,需手动开启,多个SqlSession共享,通过序列化机制实现跨会话缓存,支持LRU等淘汰策略。
两者均通过装饰器模式实现,可通过接口扩展集成第三方缓存(如Redis)。

详细解析

MyBatis 缓存分为一级缓存二级缓存,两者在作用范围、生命周期和管理方式上存在显著差异。以下是详细的介绍:


1. 一级缓存(Local Cache)

核心特性
  • 作用范围:SqlSession级别(同一个数据库会话)。
  • 默认开启:无需额外配置。
  • 生命周期:与SqlSession绑定,会话关闭或执行更新操作(增删改)时自动清空。
  • 共享性:仅对当前SqlSession可见,其他会话无法访问。
工作原理
  1. 缓存命中:在同一个SqlSession中,若多次执行相同的 SQL 和参数,MyBatis 会直接从缓存中返回结果,避免重复查询数据库。
  2. 缓存失效
    • 执行INSERT、UPDATE、DELETE操作。
    • 手动调用sqlSession.clearCache()。
    • 提交事务(sqlSession.commit())或回滚事务(sqlSession.rollback())。
示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

// 第一次查询,访问数据库

User user1 = mapper.selectUserById(1);

// 第二次查询,命中一级缓存(不访问数据库)

User user2 = mapper.selectUserById(1);

// 执行更新操作,清空缓存

mapper.updateUser(user1);

sqlSession.commit();

// 第三次查询,缓存已失效,重新访问数据库

User user3 = mapper.selectUserById(1);

sqlSession.close();


2. 二级缓存(Second Level Cache)

核心特性
  • 作用范围:Mapper级别(跨SqlSession)。
  • 手动开启:需在 XML 或注解中显式配置。
  • 生命周期:与应用生命周期一致,直到缓存被主动清除或配置过期。
  • 共享性:多个SqlSession共享同一 Mapper 的缓存。
配置方式
  1. 全局开启:在mybatis-config.xml中启用二级缓存:

    1

    2

    3

    <settings>

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

    </settings>

  2. Mapper 级配置:在 Mapper XML 中添加<cache/>标签:

    1

    2

    3

    <mapper namespace="com.example.UserMapper">

        <cache eviction="LRU" flushInterval="60000" size="1024"/>

    </mapper>

    • 参数说明
      • eviction:缓存淘汰策略(默认LRU,可选FIFO、SOFT、WEAK)。
      • flushInterval:自动刷新间隔(毫秒)。
      • size:缓存最大对象数量。
工作原理
  1. 缓存命中:多个SqlSession执行相同 SQL 时,若二级缓存存在数据,直接返回结果。
  2. 缓存失效
    • 执行INSERT、UPDATE、DELETE操作(同一 Mapper)。
    • 手动调用sqlSession.clearCache()或通过配置自动刷新。
示例

1

2

3

4

5

6

7

8

<!-- UserMapper.xml -->

<mapper namespace="com.example.UserMapper">

    <cache eviction="LRU"/>

    <select id="selectUserById" resultType="User" useCache="true">

        SELECT * FROM user WHERE id = #{id}

    </select>

</mapper>


3. 缓存优先级与执行流程

当同时启用一级和二级缓存时,MyBatis 按以下顺序查询数据:

  1. 一级缓存:优先检查当前SqlSession的缓存。
  2. 二级缓存:若一级缓存未命中,检查二级缓存。
  3. 数据库查询:若两级缓存均未命中,执行 SQL 查询,并将结果写入缓存。

4. 缓存使用注意事项

适用场景
  • 一级缓存:适合单次会话内重复查询(如循环中多次查询同一数据)。
  • 二级缓存:适合读多写少且数据实时性要求不高的场景(如配置表、静态数据)。
常见问题
  1. 脏读
    • 若多个SqlSession修改同一数据,二级缓存可能返回过期数据。
    • 解决方案:合理设置flushInterval或在更新操作后手动清除缓存。
  2. 序列化问题
    • 二级缓存默认将对象序列化存储,实体类需实现Serializable接口。
  3. 分布式环境
    • 默认二级缓存是单机缓存,分布式系统中需集成 Redis、Ehcache 等分布式缓存框架。

5. 扩展:自定义缓存

MyBatis 支持集成第三方缓存库(如 Redis、Ehcache)替换默认的 PerpetualCache。

步骤(以 Redis 为例):
  1. 添加 Redis 依赖:

    1

    2

    3

    4

    5

    <dependency>

        <groupId>org.mybatis.caches</groupId>

        <artifactId>mybatis-redis</artifactId>

        <version>1.0.0-beta2</version>

    </dependency>

  2. 配置 Mapper 使用 Redis 缓存:

    1

    2

    3

    <mapper namespace="com.example.UserMapper">

        <cache type="org.mybatis.caches.redis.RedisCache"/>

    </mapper>


6. 总结

缓存类型作用范围配置方式适用场景注意事项
一级缓存SqlSession默认开启会话内重复查询更新操作自动失效
二级缓存Mapper需显式配置<cache/>跨会话共享的静态数据避免脏读,需序列化支持
自定义缓存全局/分布式集成第三方库高并发、分布式系统需解决数据一致性问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值