【ORM 框架】MyBatis 核心组件、一级缓存 vs 二级缓存、缓存失效场景(附《思维导图》)

【ORM 框架】MyBatis 核心组件、一级缓存 vs 二级缓存、缓存失效场景(附《思维导图》) 目录MyBatis核心体系与缓存机制全解一、MyBatis核心组件体系分层架构1. 构建层配置与工厂初始化2. 会话层用户交互入口3. 代理层Mapper动态代理4. 执行层SQL执行调度5. 处理层JDBC交互核心6. 支撑层通用扩展能力7. 完整调用链路二、一级缓存 vs 二级缓存深度对比1. 一级缓存本地缓存详解2. 二级缓存全局缓存详解3. 核心维度对比表三、缓存失效场景全梳理1. 一级缓存失效的7种场景2. 二级缓存失效/脏数据的8种场景四、缓存底层核心机制1. 缓存Key生成规则2. 存储实现与淘汰策略3. 事务与缓存的同步机制五、工程实践最佳建议MyBatis核心体系与缓存机制全解一、MyBatis核心组件体系分层架构MyBatis采用分层架构设计核心组件按职责可分为6层各组件职责单一、协作完成SQL解析、执行、结果映射全流程。1. 构建层配置与工厂初始化SqlSessionFactoryBuilder采用建造者模式解析XML/注解配置文件构建全局Configuration对象最终生成SqlSessionFactory。仅用于系统初始化用完即弃。ConfigurationMyBatis全局配置容器承载数据源、Mapper映射、全局设置、插件等所有配置信息应用生命周期内单例。2. 会话层用户交互入口SqlSessionFactory工厂模式的核心负责创建SqlSession实例同时管理数据库连接池。应用运行期间单例线程安全。SqlSession用户与数据库交互的会话入口提供CRUD、事务控制等API。代表一次数据库连接会话线程不安全每次请求独立创建、用完即关闭。3. 代理层Mapper动态代理MapperProxyFactory为Mapper接口创建动态代理对象的工厂MapperProxy动态代理实现类拦截Mapper接口方法调用将方法映射为对应的MappedStatement转发给执行层处理。4. 执行层SQL执行调度Executor是SQL执行的调度核心负责缓存管理、事务管理、语句调度有3种原生实现SimpleExecutor默认执行器每次执行都创建新的Statement对象ReuseExecutor复用预编译Statement提升重复查询性能BatchExecutor批量执行优化器专门用于批量增删改场景CachingExecutor装饰器模式实现为Executor增加二级缓存能力开启二级缓存时自动包装。5. 处理层JDBC交互核心StatementHandlerJDBC Statement处理器负责Statement创建、参数设置、SQL执行对应三种实现SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。ParameterHandler参数处理器将Java类型参数转换为JDBC类型绑定到Statement中。ResultSetHandler结果集处理器将JDBC ResultSet结果集映射为Java实体对象。6. 支撑层通用扩展能力TypeHandler类型处理器完成Java类型与JDBC类型的双向转换内置常用类型处理器支持自定义扩展。Interceptor插件拦截器基于责任链模式可拦截Executor、StatementHandler、ParameterHandler、ResultSetHandler四大对象实现功能扩展。7. 完整调用链路SqlSessionFactoryBuilder → 解析配置生成Configuration → 创建SqlSessionFactory → 开启SqlSession → 获取Mapper代理对象 → MapperProxy转发给Executor → Executor查询缓存 → 无缓存则调用StatementHandler → ParameterHandler设置参数 → 执行SQL → ResultSetHandler映射结果 → 结果写入缓存 → 返回业务层。二、一级缓存 vs 二级缓存深度对比MyBatis内置两级缓存机制查询优先级为二级缓存 → 一级缓存 → 数据库。一级缓存为会话级默认开启二级缓存为全局级需手动开启。1. 一级缓存本地缓存详解作用范围单个SqlSession内部私有同一会话内共享生命周期随SqlSession创建初始化随SqlSession关闭销毁实现位置BaseExecutor类的localCache属性底层为PerpetualCache工作流程执行查询前根据SQL、参数、分页等信息生成唯一CacheKey先查询本地缓存命中则直接返回结果未命中则查询数据库将结果写入本地缓存后返回核心配置localCacheScope可选值SESSION默认整个会话期间共享缓存STATEMENT每次SQL执行后清空缓存相当于禁用一级缓存特点强制开启无法完全关闭无序列化要求性能损耗极低。2. 二级缓存全局缓存详解作用范围同一个namespaceMapper下的所有SqlSession共享生命周期与应用程序同生命周期按namespace独立存储实现位置存储于MappedStatement中由CachingExecutor装饰器管理工作流程开启二级缓存后Executor被包装为CachingExecutor查询时优先查询二级缓存命中直接返回未命中则查询一级缓存再未命中则访问数据库查询结果先存入一级缓存SqlSession事务提交后才将数据刷入二级缓存开启三条件全局开关setting namecache-enabled valuetrue/默认开启Mapper配置对应Mapper.xml中添加cache/标签实体要求缓存的POJO必须实现Serializable接口可配置项淘汰策略、刷新间隔、缓存大小、是否只读等。3. 核心维度对比表对比维度一级缓存本地缓存二级缓存全局缓存缓存级别SqlSession会话级Mapper/namespace级默认状态默认开启不可完全关闭默认关闭需手动开启共享范围单个SqlSession私有同namespace下所有会话共享生命周期与SqlSession同生共死与应用程序同生命周期实现位置BaseExecutor.localCacheMappedStatement.Cache写入时机查询完成后立即写入SqlSession事务提交后才写入序列化要求无自带实现要求POJO可序列化性能开销极低无跨会话成本有一定开销需维护全局缓存脏数据风险低仅单会话内高跨namespace易产生脏数据适用场景单次请求内重复查询读多写少、单表、一致性要求低的场景三、缓存失效场景全梳理1. 一级缓存失效的7种场景跨SqlSession访问一级缓存是会话私有不同SqlSession之间缓存完全隔离无法互相命中。同会话执行增删改同一个SqlSession中执行insert/update/delete时无论事务是否提交都会立即清空整个一级缓存。手动清空缓存调用sqlSession.clearCache()方法主动清空当前会话的一级缓存。查询条件不一致缓存Key由SQL、参数、分页、statementId等共同决定任意要素不同则Key不同无法命中。localCacheScope设为STATEMENT全局配置将本地缓存范围设为STATEMENT每次查询后自动清空一级缓存。查询语句设置flushCachetrueselect标签中配置flushCachetrue每次执行该查询前强制清空一、二级缓存。SqlSession关闭或提交SqlSession调用close()或commit()后会话销毁一级缓存随之清空。2. 二级缓存失效/脏数据的8种场景未正确开启配置全局cache-enabledfalse或Mapper未配置cache/标签二级缓存不生效。跨namespace查询二级缓存以namespace为边界不同Mapper之间缓存不共享跨Mapper查询无法命中。对应namespace执行增删改某个namespace下执行写操作时会清空该namespace下的所有二级缓存。事务未提交二级缓存必须等事务提交后才会写入未提交事务的查询结果不会进入全局缓存。跨namespace多表修改A Mapper的多表查询关联了B表B表在B Mapper中被修改时A的二级缓存不会自动刷新产生脏数据。实体类未序列化使用自带二级缓存时POJO未实现Serializable接口会抛出序列化异常缓存无法存储。查询设置useCachefalseselect标签中配置useCachefalse该查询结果不会写入二级缓存。分布式多节点环境自带二级缓存是进程内缓存集群下不同节点缓存不同步出现数据不一致与失效。四、缓存底层核心机制1. 缓存Key生成规则MyBatis通过CacheKey对象唯一标识一个查询生成要素包括MappedStatement的IDSQL语句唯一标识分页参数offset、limit原生SQL语句用户传递的查询参数值运行环境ID任意要素不同生成的CacheKey就不同缓存无法命中。2. 存储实现与淘汰策略底层存储默认PerpetualCache实现本质是HashMapObject, Object简单内存存储。淘汰策略二级缓存支持4种内置淘汰策略LRU默认最近最少使用移除最长时间未访问的对象FIFO先进先出按对象进入缓存的顺序移除SOFT软引用基于GC状态和软引用规则回收WEAK弱引用更积极地基于弱引用规则回收3. 事务与缓存的同步机制一级缓存增删改执行时立即清空缓存与事务是否提交无关保证同会话内数据一致性。二级缓存查询结果先暂存一级缓存事务提交后才刷入二级缓存回滚则直接丢弃避免脏数据进入全局缓存。写操作同步执行增删改时同步清空对应namespace的二级缓存仅单namespace范围内有效。五、工程实践最佳建议一级缓存默认即可无需额外配置单次请求内重复查询可自动命中避免长会话持有缓存及时关闭SqlSession。二级缓存谨慎使用不建议在复杂业务、多表关联场景使用极易产生脏数据仅适用于单表、读多写少、一致性要求低的场景如字典表、配置表。分布式场景替代方案集群/分布式系统中禁用MyBatis自带二级缓存改用Redis等分布式缓存保证缓存一致性与共享性。脏数据规避若使用二级缓存尽量将关联表放在同一个namespace下减少跨namespace修改。实时性查询优化对数据一致性要求高的实时查询设置useCachefalse绕过缓存直接访问数据库。