Skip to content
进阶

一句话答案

一级缓存 SqlSession 级别默认开启,二级缓存 Mapper 级别需手动开启,分布式环境建议关闭或用 Redis 替代。

核心要点

MyBatis 的核心功能:

  1. SQL 与代码分离:SQL 写在 XML 或注解中,Java 代码只调用接口方法
  2. 动态 SQL<if>, <foreach>, <choose> 等标签,根据条件拼接 SQL
  3. 结果映射(ResultMap):将 ResultSet 自动映射为 Java 对象(支持复杂嵌套关系)
  4. 一级缓存(SqlSession)/ 二级缓存(Mapper)

MyBatis 的 Mapper 接口代理实现:

  • @Mapper 接口没有实现类,由 MyBatis 通过 JDK 动态代理生成代理对象
  • 调用 Mapper 方法 → 代理对象拦截 → 根据方法名和 namespace 找到对应 SQL → 执行

MyBatis 的插件机制(Interceptor/切面):

MyBatis 允许在以下四个核心对象的指定方法上插入拦截器:

java
Executor        → update/query/commit/rollback(执行层)
StatementHandler → prepare/query/update(SQL 处理层)
ParameterHandler → setParameters(参数处理)
ResultSetHandler → handleResultSets(结果处理)

典型插件应用:

java
// 分页插件(PageHelper/MyBatis-Plus):拦截 Executor.query(),在 SQL 后追加 LIMIT
// 数据权限:拦截 query,在 WHERE 子句追加权限过滤条件(如 AND dept_id = :deptId)
// SQL 日志打印:拦截 StatementHandler,打印完整的带参数 SQL
// 数据脱敏:拦截 ResultSetHandler,对返回结果的敏感字段做脱敏处理

@Intercepts({@Signature(type=Executor.class, method="query", args={...})})
public class MyPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 前置处理
        Object result = invocation.proceed();  // 执行原方法
        // 后置处理
        return result;
    }
}
追问与易错

追问方向:

  • 一级缓存什么时候失效?
  • 二级缓存的脏数据问题?
  • 生产推荐开启二级缓存吗?

易错点:

  • ❌ MyBatis 缓存等于 Redis 缓存——是 JVM 级别的
  • ❌ 二级缓存跨 namespace 生效——只在同一 namespace

💡 记忆锚点

一级缓存 = 个人笔记本(SqlSession级别,默认开,关了就没了),二级缓存 = 班级共享笔记(Mapper级别,要手动开)。分布式环境共享笔记会过时(脏数据),建议用Redis替代。Mapper接口没有实现类,全靠JDK动态代理撑场面。