首页技术栈归档照片墙音乐日记随想收藏夹友链留言关于

MyBatis 缓存与插件

写作时间:2026-07-08

MyBatis 缓存与插件

一级缓存(SqlSession 级别)

默认开启,同一个 SqlSession 内相同查询只执行一次 SQL:

try (SqlSession session = factory.openSession()) {
  UserMapper mapper = session.getMapper(UserMapper.class);
  User u1 = mapper.selectById(1L);  // 查数据库
  User u2 = mapper.selectById(1L);  // 命中一级缓存
  System.out.println(u1 == u2);  // true
}

一级缓存失效场景:

  • 不同 SqlSession
  • SqlSession 内执行了 INSERT/UPDATE/DELETE
  • 手动 clearCache()

二级缓存(Mapper 级别)

跨 SqlSession 共享,需显式开启:

<!-- mybatis-config.xml -->
<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>
<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
  <cache eviction="LRU" flushInterval="60000" size="512" readOnly="false"/>
</mapper>

可选属性:

属性 说明 默认
eviction 回收策略 LRU
flushInterval 刷新间隔(ms) 不刷新
size 最大对象数 1024
readOnly 只读=true 性能高 false

自定义缓存

实现 Cache 接口接 Redis/Ehcache:

public class RedisCache implements Cache {
  private final String id;
  public RedisCache(String id) { this.id = id; }
  @Override public String getId() { return id; }
  @Override public void putObject(Object key, Object value) {
    redis.set(key.toString(), serialize(value));
  }
  @Override public Object getObject(Object key) {
    return deserialize(redis.get(key.toString()));
  }
  @Override public Object removeObject(Object key) {
    return redis.del(key.toString());
  }
  @Override public void clear() { /* 清空 namespace 缓存 */ }
  @Override public int getSize() { return redis.dbSize().intValue(); }
}

配置:

<cache type="com.example.cache.RedisCache"/>

插件机制(Interceptor)

MyBatis 允许拦截以下方法:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

分页插件原理

PageHelper 就是通过拦截 Executor.query() 实现的:

@Intercepts({
  @Signature(type = Executor.class, method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PageInterceptor implements Interceptor {
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    // 1. 获取参数中的 Page 对象
    // 2. 执行 COUNT 查询获取总数
    // 3. 修改原 SQL 添加 LIMIT 子句
    // 4. 执行分页查询
    return invocation.proceed();
  }
}

使用 PageHelper

// Maven
// pagehelper-spring-boot-starter 1.4.7

PageHelper.startPage(1, 10);
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
// pageInfo.getTotal();  // 总记录数
// pageInfo.getPages();  // 总页数
avatar

yuanyourdomain

写代码,做研究,记录生活。

RECOMMENDED

MyBatis 动态 SQL

2026-07-08

Nginx 基础入门

2026-07-08

Maven 多模块与私服

2026-07-08