深入剖析 MyBatis 缓存机制:从一级缓存到 EhCache 集成优化

深入剖析 MyBatis 缓存机制:从一级缓存到 EhCache 集成优化

在大型应用中,频繁的数据库读写会成为性能瓶颈。MyBatis 提供了完善的缓存机制,通过减少 I/O 操作与数据库查询次数,显著提升系统性能。本文将结合示例,详细介绍 MyBatis 的一级缓存、二级缓存,以及如何集成第三方缓存(以 EhCache 为例)。


1. MyBatis 缓存概述

  • 缓存(Cache):将数据临时存储在内存中,以减少对数据库的直接访问,从而提高程序执行效率。

  • MyBatis 缓存类型

    1. 一级缓存(本地缓存):默认开启,作用域为同一个 SqlSession

    2. 二级缓存(全局缓存):作用域为同一个 SqlSessionFactory,需要手动配置。

    3. 第三方缓存集成:例如 EhCache、Memcached 等。

  • 适用范围:仅针对查询(SELECT)语句,Insert/Update/Delete 操作不会被缓存。


2. 一级缓存

特点

  • 默认开启,无需额外配置。

  • 缓存在同一个 SqlSession 生命周期内生效——同一条 SQL、同一参数、同一会话下重复查询时命中缓存。

失效场景

  1. 不同 SqlSession

  2. 查询条件变化

  3. 手动清理

    sqlSession.clearCache();  // 清空一级缓存
  1. 出现写操作(INSERT/UPDATE/DELETE)

    只要同一 SqlSession 中执行了任意写操作,即使针对不同表,也会清空一级缓存。


3. 二级缓存

作用域

  • 针对同一个 SqlSessionFactory,多个 SqlSession 之间可共享。

配置步骤

  1. 全局开关mybatis-config.xml 中,默认为 true

    <setting name="cacheEnabled" value="true"/>
  2. Mapper 文件启用二级缓存

    <!-- 在 SqlMapper.xml 根节点内 -->
    <cache/>
  3. 实体类实现序列化

    public class User implements Serializable { ... }
  4. 提交或关闭 SqlSession 后写入缓存

    写操作(增删改)同样会导致二级缓存失效。

可选属性(以 <cache> 标签属性形式配置)

属性含义默认值
eviction缓存淘汰算法:LRU / FIFO / SOFT / WEAKLRU
flushInterval缓存刷新间隔(毫秒),不设置则不自动刷新
readOnly是否只读:true 返回同一对象(性能高),false 返回克隆对象false
size最大缓存对象数量1024


4. 集成 EhCache

为获得更丰富的缓存特性与更高的扩展性,常用 EhCache 替代内置二级缓存。

  1. 添加依赖(Maven)

    <!-- MyBatis 与 EhCache 集成组件 -->
    <dependency>
     <groupId>org.mybatis.caches</groupId>
     <artifactId>mybatis-ehcache</artifactId>
     <version>1.2.2</version>
    </dependency>
    <!-- 日志依赖(推荐 Logback) -->
    <dependency>
     <groupId>ch.qos.logback</groupId>
     <artifactId>logback-classic</artifactId>
     <version>1.2.11</version>
    </dependency>
  2. 创建 ehcache.xml(放置于类路径根目录)

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
            updateCheck="false">
     <diskStore path="java.io.tmpdir"/>
     <defaultCache
       eternal="false"
       maxElementsInMemory="1000"
       overflowToDisk="false"
       timeToIdleSeconds="0"
       timeToLiveSeconds="600"
       memoryStoreEvictionPolicy="LRU" />
    </ehcache>
  3. 修改 Mapper 文件,指定使用 EhCache

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  4. 测试示例

    @Test
    public void testEhCache() {
       SqlSessionFactory factory = new SqlSessionFactoryBuilder()
          .build(Resources.getResourceAsStream("mybatis-config.xml"));
       // 第一次查询,写入二级缓存
       try (SqlSession s1 = factory.openSession()) {
           Car car1 = s1.getMapper(CarMapper.class).selectById(83L);
           System.out.println(car1);
      }
       // 第二次查询,命中缓存
       try (SqlSession s2 = factory.openSession()) {
           Car car2 = s2.getMapper(CarMapper.class).selectById(83L);
           System.out.println(car2);
      }
    }

  • 微信
  • 赶快加我聊天吧
  • QQ
  • 赶快加我聊天吧
  • weinxin
三桂

发表评论 取消回复 您未登录,登录后才能评论,前往登录