13. 说说 MyBatis 的缓存机制?

MyBatis 提供了一级缓存和二级缓存两种缓存机制,用于提高应用程序的性能,减少数据库的访问次数。缓存机制是 MyBatis 的一个重要特性,通过缓存可以在一定程度上减少对数据库的访问,从而提高查询性能。

1. 一级缓存(Local Cache)

作用范围:一级缓存是 MyBatis 默认开启的缓存机制,作用于 SqlSession 级别。

特点

  • 生命周期:一级缓存的生命周期与 SqlSession 相同。在同一个 SqlSession 中执行多次相同的查询(条件相同),如果缓存中已经存在结果,则直接返回缓存中的结果,而不再向数据库发送查询请求。

  • 存储方式:一级缓存是基于 PerpetualCache 和 HashMap 实现的,存储查询结果的键值对,键为 SQL 语句的字符串及其参数,值为查询结果。

  • 失效条件:在 SqlSession 中,如果执行了 INSERTUPDATEDELETE 操作,一级缓存会被清空,确保数据的一致性。另外,手动清空缓存或关闭 SqlSession 也会使一级缓存失效。

示例

SqlSession session = sqlSessionFactory.openSession();
User user1 = session.selectOne("selectUserById", 1); // 从数据库查询
User user2 = session.selectOne("selectUserById", 1); // 从一级缓存中获取结果

2. 二级缓存(Global Cache)

作用范围:二级缓存是 MyBatis 的全局缓存机制,作用于 Mapper 映射器级别。即同一个 Mapper 映射器中的查询结果可以被不同的 SqlSession 实例共享。

特点

  • 默认关闭:二级缓存默认是关闭的,需要在配置文件或 Mapper 文件中显式开启。

  • SqlSession:二级缓存是跨 SqlSession 的,多个 SqlSession 可以共享同一个 Mapper 中的缓存数据。

  • 存储方式:二级缓存也是基于 PerpetualCache 实现的,并且需要将缓存对象序列化,因此缓存对象必须实现 Serializable 接口。

  • 失效条件:当执行 INSERTUPDATEDELETE 等修改操作时,二级缓存会被清空。同时,事务提交后,查询结果才会写入二级缓存。

启用二级缓存

  1. 在 MyBatis 全局配置文件中启用二级缓存

    
        
    
  2. 在具体的 Mapper 文件中配置二级缓存

    
        
        
        
        
    

示例

// 第一次查询,结果存入二级缓存
try (SqlSession session1 = sqlSessionFactory.openSession()) {
    UserMapper mapper1 = session1.getMapper(UserMapper.class);
    User user1 = mapper1.selectUserById(1);
}
​
// 第二次查询,不同的 SqlSession 实例,结果从二级缓存中获取
try (SqlSession session2 = sqlSessionFactory.openSession()) {
    UserMapper mapper2 = session2.getMapper(UserMapper.class);
    User user2 = mapper2.selectUserById(1);
}

3. 一级缓存与二级缓存的比较

特性 一级缓存 二级缓存
作用范围 SqlSession 级别 Mapper 映射器级别,跨 SqlSession
默认状态 默认开启 默认关闭
缓存生命周期 SqlSession 相同 Mapper 相同
缓存失效 SqlSession 执行写操作时清空 Mapper 执行写操作时清空
缓存共享 不同的 SqlSession 之间不共享 不同的 SqlSession 之间共享

4. 配置和管理二级缓存

MyBatis 提供了多种方式来配置和管理二级缓存:

  • 缓存策略:可以通过 标签的 eviction 属性配置缓存回收策略。默认使用 LRU(最近最少使用),其他选项包括 FIFO(先进先出)、SOFT(软引用)、WEAK(弱引用)。

  • 刷新间隔:通过 flushInterval 属性配置缓存的刷新间隔。默认情况下不会自动刷新,可以设置为毫秒级的刷新间隔。

  • 缓存大小:通过 size 属性设置缓存的最大对象数量。

  • 只读模式:通过 readOnly 属性设置缓存是否为只读模式。只读模式下,缓存中的对象在缓存期间不可修改,适合提高并发性能。

示例配置


    size="512"              
    readOnly="true"         
/>

5. 使用注意事项

  • 事务管理:二级缓存和事务管理紧密相关,只有在事务提交后,查询结果才会存入二级缓存。如果事务回滚,缓存不会更新。

  • 对象序列化:由于二级缓存需要将对象序列化,所有被缓存的对象必须实现 Serializable 接口。

  • 一致性问题:二级缓存会在更新数据时失效,但在高并发情况下,可能会有短暂的缓存不一致问题,需要根据实际情况权衡缓存带来的性能提升与一致性问题。

6. 总结

  • 一级缓存:每个 SqlSession 维护自己的一级缓存,默认开启,不同 SqlSession 之间不共享。适用于单个会话内重复查询的场景。

  • 二级缓存:二级缓存是跨 SqlSession 的全局缓存,默认关闭,需要手动开启和配置。适用于多次会话之间需要共享查询结果的场景。

通过合理配置 MyBatis 的一级和二级缓存,可以显著提升应用程序的性能,特别是在读多写少的场景中,缓存机制可以有效减少数据库访问次数,提升查询效率。

你可能感兴趣的:(Mybatis笔记,mybatis,java,spring)