我们是由枫哥组建的IT技术团队成立于2017年致力于帮助IT从业者提供实力成功入职理想企业我们提供一对一学习辅导由知名大厂导师指导分享Java技术、参与项目实战等服务并为学员定制职业规划全面提升竞争力过去8年我们已成功帮助数千名求职者拿到满意的OfferIT枫斗者、IT枫斗者-Java面试突击。场景MyBatis 持久层开发需要跨 SqlSession 共享热点数据进一步减少数据库访问压力提升查询性能。结论二级缓存基于 Mapper namespace 实现数据共享增删改操作并执行 commit 后会自动清空对应namespace缓存缓存实体类必须实现 Serializable 序列化接口。产出彻底掌握二级缓存底层原理、完整配置步骤、commit 缓存清空机制、useCache/flushCache 高级缓存控制技巧。一、版本功能矩阵MyBatis 3.5.x本文所有内容基于**MyBatis 3.5**稳定版本所有特性均已验证可用适配日常开发及面试场景功能状态详细说明二级缓存默认行为⚠️ 需手动开启cacheEnabled 全局默认 true但必须在 Mapper 显式配置 才真正生效Mapper namespace 作用域✅ 已验证多个 SqlSession 共享同一 namespace 下的缓存数据同namespace缓存共享✅ 已验证不同Mapper文件namespace相同时会共用同一个缓存区域commit自动清空缓存✅ 已验证INSERT/UPDATE/DELETE操作后执行commit会清空当前namespace所有缓存Serializable序列化要求✅ 已验证缓存实体必须实现该接口支持磁盘、Redis等介质的序列化与反序列化useCache单条SQL控制✅ 已验证可手动关闭单条select语句二级缓存默认true开启flushCache自动刷新✅ 已验证增删改语句默认flushCachetrue执行后自动刷新缓存无需手动配置自定义Cache实现✅ 已验证通过cache标签type参数指定自定义Cache接口实现类二、MyBatis 两级缓存核心区别MyBatis 内置一级缓存 二级缓存两级缓存机制核心差异极大也是面试高频考点一级缓存SqlSession级别默认开启作用域仅限当前数据库会话会话关闭后缓存失效无法跨会话共享数据二级缓存Mapper Namespace级别默认不生效需手动配置开启支持跨 SqlSession 共享缓存数据作用域为整个Mapper命名空间简单来说二级缓存就是为了解决一级缓存无法跨会话共享热点数据的问题大幅减少重复SQL查询减轻数据库压力。三、二级缓存核心工作原理二级缓存是跨会话共享的全局缓存区域以 Mapper 的 namespace 为最小隔离单位同一namespace下的所有SqlSession、所有查询语句共享同一块缓存空间。核心特性多个Mapper文件若namespace完全一致会共用同一个缓存区容易出现缓存污染开发中需保证namespace唯一。1. 查询执行流程二级缓存优先MyBatis查询数据时缓存优先级二级缓存 一级缓存 数据库程序发起查询请求优先从二级缓存中匹配数据二级缓存未命中继续查询当前SqlSession的一级缓存一级缓存仍未命中执行SQL查询数据库将查询结果同时存入一级缓存当前会话和二级缓存全局共享2. 更新执行流程自动清空缓存为保证数据最终一致性MyBatis内置缓存刷新机制执行 INSERT/UPDATE/DELETE 增删改操作调用 sqlSession.commit() 提交事务自动清空当前namespace下的所有二级缓存数据下次查询重新访问数据库生成新缓存四、二级缓存优缺点分析✅ 优点减少数据库访问热点数据一次查询、多次复用大幅提升查询性能跨会话共享数据突破一级缓存会话限制适配多请求、多会话场景轻量无侵入配置简单无需额外编码原生支持自动维护❌ 缺点数据一致性延迟其他服务/第三方工具修改数据库数据后本地缓存不会自动更新存在脏数据风险占用内存资源长期缓存热点数据会占用应用内存增加维护复杂度需手动管控缓存失效、序列化、缓存污染等问题五、二级缓存完整开启步骤二级缓存全局默认开启但不生效必须完成「全局配置Mapper配置实体序列化」三步配置缺一不可。1. 全局开启二级缓存sqlMapConfig.xml在全局配置文件中开启cacheEnabled默认值为true建议显式配置便于维护settings!-- 全局开启二级缓存 --settingnamecacheEnabledvaluetrue//settings2. Mapper映射文件开启缓存在需要使用二级缓存的 Mapper.xml 文件中添加空的 标签代表当前namespace开启二级缓存!-- 当前Mapper命名空间开启二级缓存 --cache/拓展可通过标签参数自定义缓存规则也可通过type参数指定自定义Cache实现类。3. 实体类实现Serializable序列化接口必做二级缓存数据可存储在内存、磁盘、Redis等介质需要支持序列化与反序列化所有缓存实体类必须实现 Serializable 接口否则直接报错。importlombok.AllArgsConstructor;importlombok.Builder;importlombok.Data;importlombok.NoArgsConstructor;importjava.io.Serializable;importjava.util.Date;importjava.util.List;DataBuilderAllArgsConstructorNoArgsConstructor// 二级缓存强制要求实现序列化接口publicclassWzkUserimplementsSerializable{privateintid;privateStringusername;privateStringpassword;privateDatebirthday;privateListWzkOrderorderList;privateListWzkRoleroleList;}六、代码实战测试测试一跨SqlSession缓存共享验证模拟两个不同的数据库会话验证二级缓存跨会话共享特性importorg.apache.ibatis.io.Resources;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibatis.session.SqlSessionFactory;importorg.apache.ibatis.session.SqlSessionFactoryBuilder;importjava.io.IOException;importjava.io.InputStream;importjava.util.List;publicclassWzkicuCache03{publicstaticvoidmain(String[]args)throwsIOException{// 加载全局配置文件InputStreaminputStreamResources.getResourceAsStream(sqlMapConfig.xml);SqlSessionFactorysqlSessionFactorynewSqlSessionFactoryBuilder().build(inputStream);// 创建两个独立的SqlSession会话SqlSessionsqlSession1sqlSessionFactory.openSession();SqlSessionsqlSession2sqlSessionFactory.openSession();UserMapperuserMapper1sqlSession1.getMapper(UserMapper.class);UserMapperuserMapper2sqlSession2.getMapper(UserMapper.class);// 第一次查询无缓存执行SQL查库存入二级缓存ListWzkUserusers1userMapper1.findAll();sqlSession1.close();// 第二次查询跨会话读取二级缓存不执行SQLListWzkUserusers2userMapper2.findAll();sqlSession2.close();}}运行结果仅第一条查询执行SQL第二次查询命中二级缓存无SQL执行缓存命中率提升至0.5。测试二commit缓存自动清空机制验证增删改commit操作后二级缓存自动清空避免数据脏读importorg.apache.ibatis.io.Resources;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibatis.session.SqlSessionFactory;importorg.apache.ibatis.session.SqlSessionFactoryBuilder;importjava.io.IOException;importjava.io.InputStream;importjava.util.List;publicclassWzkicuCache04{publicstaticvoidmain(String[]args)throwsIOException{InputStreaminputStreamResources.getResourceAsStream(sqlMapConfig.xml);SqlSessionFactorysqlSessionFactorynewSqlSessionFactoryBuilder().build(inputStream);// 三个独立会话SqlSessionsqlSession1sqlSessionFactory.openSession();SqlSessionsqlSession2sqlSessionFactory.openSession();SqlSessionsqlSession3sqlSessionFactory.openSession();UserMapperuserMapper1sqlSession1.getMapper(UserMapper.class);UserMapperuserMapper2sqlSession2.getMapper(UserMapper.class);UserMapperuserMapper3sqlSession3.getMapper(UserMapper.class);// 第一次查询生成二级缓存ListWzkUserusers1userMapper1.findAll();sqlSession1.close();// 执行更新操作并提交事务WzkUserwzkUserWzkUser.builder().id(1).username(wzk-update).password(123-update).build();userMapper2.updateById(wzkUser);// commit触发二级缓存清空核心机制sqlSession2.commit();sqlSession2.close();// 缓存已清空重新查询数据库ListWzkUserusers3userMapper3.findAll();sqlSession3.close();}}运行结果更新并commit后二级缓存被清空第三次查询重新执行SQL缓存命中率为0完美验证缓存失效机制。七、高级缓存配置useCache flushCache1. useCache控制单条查询缓存作用于单条select语句默认true开启二级缓存设置为false可禁用当前查询的缓存实时查询最新数据库数据。适用场景高频更新、对数据一致性要求极高的查询接口。selectidfindAllresultMapuserMapuseCachefalseselect *,o.id oid from wzk_user u left join wzk_orders o on u.ido.uid;/select2. flushCache自动刷新缓存增删改语句默认flushCachetrue执行并commit后自动刷新清空缓存无需手动配置。作用最大程度避免数据库与缓存数据不一致保证业务数据准确性。八、错误速查卡开发高频坑故障症状根因分析定位方式修复方案开启二级缓存报序列化异常实体类未实现Serializable接口查看报错实体类声明实体类手动实现Serializable接口跨SqlSession查询始终走数据库Mapper未配置标签检查对应Mapper.xml文件Mapper文件添加开启命名空间缓存缓存命中率始终为0全局cacheEnabled未开启检查sqlMapConfig.xml配置设置cacheEnabledtrue增删改后缓存数据不刷新未执行commit事务提交检查代码是否调用commit()增删改操作后必须执行sqlSession.commit()指定查询始终不走缓存语句配置了useCachefalse检查select标签属性移除配置或根据业务按需保留多Mapper缓存数据互相污染多个Mapper namespace重复核对所有Mapper命名空间用手动指定共享空间缓存与数据库数据不一致外部程序修改数据库数据排查非MyBatis写操作缩短缓存过期时间或接入分布式缓存通知机制九、全文核心总结MyBatis二级缓存是Namespace级别、跨SqlSession共享的全局缓存用于优化热点查询性能开启三要素全局cacheEnabledtrue Mapper配置 实体类实现Serializable序列化核心失效机制增删改 commit 自动清空当前namespace所有缓存缓存执行优先级二级缓存 一级缓存 数据库useCache控制单条查询缓存flushCache默认开启保障数据一致性同namespace多Mapper会共享缓存开发中需规范命名避免缓存污染⭐️推荐:Offer训练营介绍Java 面试 后端通用面试八股文Java后端企业级实战面试Java后端校招算法学习