JAVA面试宝典 - 《MyBatis 进阶:插件开发与二级缓存》

文章目录

  • [🚀《MyBatis 进阶:插件开发与二级缓存》](#🚀《MyBatis 进阶:插件开发与二级缓存》)
    • [一、开场引导:MyBatis 不只是 ORM 工具](#一、开场引导:MyBatis 不只是 ORM 工具)
    • [二、MyBatis 插件机制详解](#二、MyBatis 插件机制详解)
      • [2.1 插件本质是"执行栈拦截器"](#2.1 插件本质是“执行栈拦截器”)
      • [2.2 插件开发实战:记录 SQL 执行耗时](#2.2 插件开发实战:记录 SQL 执行耗时)
      • [2.3 插件原理揭秘](#2.3 插件原理揭秘)
    • [三、MyBatis 二级缓存机制](#三、MyBatis 二级缓存机制)
      • [3.1 一级缓存 vs 二级缓存](#3.1 一级缓存 vs 二级缓存)
      • [3.2 启用二级缓存的步骤](#3.2 启用二级缓存的步骤)
    • [3.3 缓存失效与扩展](#3.3 缓存失效与扩展)
    • [四、实战案例:自定义 Cache 接入 Redis](#四、实战案例:自定义 Cache 接入 Redis)
      • [4.1 实现 Cache 接口](#4.1 实现 Cache 接口)
      • [4.2 注册自定义缓存](#4.2 注册自定义缓存)
    • 五、常见问题与性能建议
    • 六、总结
    • [📚 推荐阅读](#📚 推荐阅读)

🚀《MyBatis 进阶:插件开发与二级缓存》

🎯 目标读者

已掌握 MyBatis 基础映射与 Mapper 使用,

想深入了解 MyBatis 插件机制与二级缓存原理及实践。


一、开场引导:MyBatis 不只是 ORM 工具

MyBatis 以 灵活可插拔轻量级 著称,但你是否真正了解它底层"魔法"?

  • 插件 能干预 SQL 执行流程:日志、权限、监控......
  • 二级缓存SqlSession 提升查询性能:内存、分布式都可扩展!

问题抛出:

  • 如何开发一个统计 SQL 执行耗时的插件?
  • 二级缓存如何从内存跑到 Redis?

二、MyBatis 插件机制详解

2.1 插件本质是"执行栈拦截器"

类比:Spring AOP 是"分层切面",MyBatis 插件更像给执行栈每一站"排队拦车"------

每到关键节点,拦下并加入自定义逻辑,再放行。

可拦截的四大方法(对应核心四大处理器):

处理器 可拦截方法
Executor query()update()
ParameterHandler setParameters()
ResultSetHandler handleResultSets()
StatementHandler prepare()parameterize()batch()

2.2 插件开发实战:记录 SQL 执行耗时

步骤一:实现 Interceptor
java 复制代码
@Intercepts({
  @Signature(type = Executor.class,
             method = "query",
             args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class SqlTimingInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long start = System.nanoTime();
        Object result = invocation.proceed();
        long elapsedMs = (System.nanoTime() - start) / 1_000_000;
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
        if (elapsedMs > 100) {
            System.err.printf("[Slow SQL] %s took %d ms%n", ms.getId(), elapsedMs);
        }
        return result;
    }
    @Override public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    @Override public void setProperties(Properties props) { }
}
步骤二:注册插件
xml 复制代码
<plugins>
  <plugin interceptor="com.example.mybatis.SqlTimingInterceptor"/>
</plugins>

2.3 插件原理揭秘

  1. Plugin.wrap(target, interceptor)
  • 如果目标类型匹配 @Signature,则用 JDK 动态代理或 CGLIB 生成代理对象。
  1. 链式拦截
  • 多个插件按配置顺序"嵌套",先注册的最外层,最后执行的最内层。
  1. 执行流程
java 复制代码
ExecutorImpl.query() 
  → interceptor1.intercept() 
    → interceptor2.intercept() 
      → 实际 query 方法

三、MyBatis 二级缓存机制

3.1 一级缓存 vs 二级缓存

缓存类型 范围 生命周期 默认开启 可配置性
一级缓存 单个 SqlSession 会话内 不可关闭
二级缓存 Mapper 映射空间 SqlSession 可开启/禁用
  • 一级缓存:类似图书馆阅览室,只在"当天"可重复借阅。

  • 二级缓存:像书架借书,可以跨会话"长期"缓存(甚至跨进程)。

3.2 启用二级缓存的步骤

  1. Mapper 接口/映射文件 加上注解或 XML:
java 复制代码
@CacheNamespace(implementation=RedisCache.class, eviction=FifoCache.class, flushInterval=60000)
public interface UserMapper { ... }
  1. 实体类实现 Serializable
  2. 查询方法返回可序列化对象,不能是流或 ResultHandler

写操作(insert/update/delete)会清空对应 namespace 下的二级缓存。

3.3 缓存失效与扩展

  • Session 关闭:一级缓存清空
  • 写操作:清空二级缓存
  • 命名空间隔离:不同 Mapper 之间不共享
  • 自定义缓存:可实现 org.apache.ibatis.cache.Cache 接口,用 Redis、Guava 等

四、实战案例:自定义 Cache 接入 Redis

4.1 实现 Cache 接口

java 复制代码
public class RedisCache implements Cache {
    private final String id;
    private RedisTemplate<String,Object> redis;
    public RedisCache(String id) { this.id = id; }
    @Override public String getId() { return id; }
    @Override public void putObject(Object key, Object value) {
        redis.opsForHash().put(id, key.toString(), value);
    }
    @Override public Object getObject(Object key) {
        return redis.opsForHash().get(id, key.toString());
    }
    @Override public Object removeObject(Object key) {
        return redis.opsForHash().delete(id, key.toString());
    }
    @Override public void clear() {
        redis.delete(id);
    }
    @Override public int getSize() {
        return redis.opsForHash().size(id).intValue();
    }
}

4.2 注册自定义缓存

xml 复制代码
<cache type="com.example.mybatis.RedisCache"/>

发布到分布式集群时,所有节点都可共享同一 Redis 二级缓存。

五、常见问题与性能建议

问题 建议
插件过多影响性能 精简插件链,按需拦截;生产环境剔除非必要插件
二级缓存命中率低 减少写操作频率;针对热点数据单独设计缓存清理策略
数据一致性难保证 配合消息队列或 Redis 发布/订阅实现失效通知
统计所有 SQL Executor.query()update() 中同时拦截

六、总结

  • 插件机制:通过 Interceptor 拦截执行栈,灵活扩展 SQL 监控、审计、权限等功能。
  • 二级缓存:跨会话缓存结果,默认内存实现,可自定义 Redis、Guava 等持久化方式。
  • 进阶能力:掌握插件与缓存设计,意味着你已步入 MyBatis 的"进阶圈",能让 ORM 不止"映射",还能"加速"与"智能化"!

📚 推荐阅读

  • MyBatis 官方文档:插件开发 & 缓存章节
  • MyBatis 源码深度解析
  • Redis 官方文档:Hash 结构与内存优化
相关推荐
洋不写bug1 分钟前
链表补充练习,双链表的模拟实现
java·数据结构·链表·双链表·底层实现
后台模板学习5 分钟前
用 IM 即时聊天项目一次讲清消息去重算法的踩坑与解决方案
java·数据库·spring
秋名RG7 分钟前
2026/6/15 系统故障复盘与整改方案
java·架构
今天要早睡_9 分钟前
C++ 核心语法速过:命名空间、引用、函数重载与 nullptr 深度解析
android·java·c++
南讯股份Nascent12 分钟前
2026年CRM技术选型观察:当“数据打通“成为第一需求,电商CRM的架构价值在哪里
java·大数据·用户运营
心易行者18 分钟前
Python自动化测试7步落地法:用python在线运行省掉90%环境配置时间
java·开发语言·人工智能·python·log4j·ai编程
霸道流氓气质1 小时前
Spring AI 技术细节:VectorStore 多库统一抽象
java·人工智能·spring
今天AI了吗1 小时前
Codex 配置自定义 AI API 完整指南:从零到一接入你的专属模型
java·人工智能·python·数据分析·embedding
数智启示录1 小时前
PostgreSQL 执行计划实战(第 9 篇):SQL 和索引没变,计划为什么突然慢一百倍
数据库·经验分享·sql·postgresql·面试
学长毕业设计1 小时前
基于SpringBoot的健康食谱管理系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端