手机做直播官方网站免费中文WordPress主题
2026/2/17 5:54:08 网站建设 项目流程
手机做直播官方网站,免费中文WordPress主题,淮安网站seo,应用市场一、初识MyBatis缓存 在正式开始之前#xff0c;让我们先来了解MyBatis的整体架构。MyBatis采用分层设计#xff0c;而缓存模块作为基础支撑层的核心组件#xff0c;承担着提升查询性能的重要使命。缓存的价值何在#xff1f; 想象这样一个场景#xff1a;你的系统每秒需要…一、初识MyBatis缓存在正式开始之前让我们先来了解MyBatis的整体架构。MyBatis采用分层设计而缓存模块作为基础支撑层的核心组件承担着提升查询性能的重要使命。缓存的价值何在想象这样一个场景你的系统每秒需要查询1000次用户信息。无缓存时1000次数据库查询/秒有缓存时1次数据库查询 999次内存读取/秒性能提升近1000倍MyBatis的两级防线MyBatis提供了两级缓存机制就像双重保险二、缓存架构MyBatis的缓存设计堪称教科书级别的装饰器模式应用。Cache接口缓存的灵魂所有缓存实现都遵循这个核心接口publicinterfaceCache{StringgetId();// 缓存标识voidputObject(Objectkey,Objectvalue);// 存入缓存ObjectgetObject(Objectkey);// 获取缓存ObjectremoveObject(Objectkey);// 移除缓存voidclear();// 清空缓存intgetSize();// 缓存大小ReadWriteLockgetReadWriteLock();// 读写锁}装饰器大家族MyBatis通过装饰器模式为缓存穿衣服每个装饰器赋予缓存一种新能力PerpetualCache万丈高楼平地起这是最基础的缓存实现简单而高效publicclassPerpetualCacheimplementsCache{privatefinalStringid;privatefinalMapObject,ObjectcachenewHashMap();OverridepublicvoidputObject(Objectkey,Objectvalue){cache.put(key,value);}OverridepublicObjectgetObject(Objectkey){returncache.get(key);}// ... 其他方法实现}三、一级缓存会话的专属记忆一级缓存是SqlSession级别的缓存默认开启无需配置。工作原理解析一级缓存的核心逻辑在BaseExecutor中实现publicEListEquery(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler){//创建缓存键CacheKeykeycreateCacheKey(ms,parameter,rowBounds,boundSql);//先查缓存ListElist(ListE)localCache.getObject(key);if(list!null){returnlist;// 缓存命中}//缓存未命中查询数据库listqueryFromDatabase(ms,parameter,rowBounds,resultHandler,key,boundSql);//结果写入缓存localCache.putObject(key,list);returnlist;}CacheKey缓存的身份证CacheKey由多个元素组成确保唯一性CacheKey的组成├──MappedStatement的ID ├── 查询参数 ├── 分页信息RowBounds ├── SQL语句 └── 环境ID判断缓存命中时这些元素必须完全一致Overridepublicbooleanequals(Objectobject){finalCacheKeycacheKey(CacheKey)object;returnhashcodecacheKey.hashcode// 哈希码相同checksumcacheKey.checksum// 校验和相同countcacheKey.count// 元素数量相同updateList.equals(cacheKey.updateList);// 元素列表相同}五种失效场景一级缓存在以下情况会被清空执行增删改操作手动清空提交事务回滚事务关闭会话Overridepublicintupdate(MappedStatementms,Objectparameter){clearLocalCache();//清空缓存returndoUpdate(ms,parameter);}session.clearCache();//主动清理session.commit();//提交时清空session.rollback();//回滚时清空session.close();//会话结束缓存消失实战演示SqlSessionsessionsqlSessionFactory.openSession();UserMappermappersession.getMapper(UserMapper.class);// 第一次查询 - 访问数据库Useruser1mapper.selectById(1L);System.out.println(首次查询: user1);// 第二次查询 - 从缓存获取Useruser2mapper.selectById(1L);System.out.println(再次查询: user2);// 验证是否为同一对象System.out.println(同一对象? (user1user2));//truesession.close();四、二级缓存跨会话的共享空间二级缓存是Mapper级别的缓存可以在不同SqlSession之间共享数据。开启二级缓存在Mapper XML中添加配置mapper namespacecom.example.mapper.UserMapper!--开启二级缓存--cache evictionLRUflushInterval60000size1024readOnlytrue/select idselectByIdresultTypeUserSELECT*FROM t_userWHEREid#{id}/select/mapper配置参数详解四大淘汰策略LRU推荐FIFOSOFTWEAKcache evictionLRU/最近最少使用淘汰最久未访问的数据cache evictionFIFO/先进先出按写入顺序淘汰cache evictionSOFT/软引用内存不足时才回收cache evictionWEAK/弱引用GC时即可回收CachingExecutor二级缓存的指挥官publicclassCachingExecutorimplementsExecutor{privatefinalTransactionalCacheManagertcmnewTransactionalCacheManager();OverridepublicEListEquery(...){Cachecachems.getCache();if(cache!null){//尝试从二级缓存获取ListElist(ListE)tcm.getObject(cache,key);if(list!null){returnlist;//命中}}//委托给BaseExecutor查询会走一级缓存ListElistdelegate.query(...);//结果写入二级缓存if(cache!null){tcm.putObject(cache,key,list);}returnlist;}}TransactionalCache事务缓存管家事务缓存确保只有提交后的数据才会进入二级缓存publicclassTransactionalCacheimplementsCache{privatefinalMapObject,ObjectentriesToAddOnCommit;OverridepublicvoidputObject(Objectkey,Objectvalue){//暂存不立即写入entriesToAddOnCommit.put(key,value);}publicvoidcommit(){// 提交时才真正写入缓存for(Map.EntryObject,Objectentry:entriesToAddOnCommit.entrySet()){delegate.putObject(entry.getKey(),entry.getValue());}}publicvoidrollback(){// 回滚时丢弃暂存数据entriesToAddOnCommit.clear();}}跨会话共享示例//会话1SqlSessionsession1sqlSessionFactory.openSession();UserMappermapper1session1.getMapper(UserMapper.class);Useruser1mapper1.selectById(1L);System.out.println(会话1查询: user1);session1.commit();//提交写入二级缓存session1.close();//会话2SqlSessionsession2sqlSessionFactory.openSession();UserMappermapper2session2.getMapper(UserMapper.class);Useruser2mapper2.selectById(1L);//从二级缓存获取System.out.println(会话2查询: user2);//对比结果System.out.println(同一对象? (user1user2));//falseSystem.out.println(值相等? user1.equals(user2));//truesession2.close();五、缓存命中流程全景理解缓存的完整查询流程是优化性能的关键。完整查询链路查询请求 ↓ 检查二级缓存 ├─ 命中 → 直接返回 └─ 未命中 ↓ 检查一级缓存 ├─ 命中 → 直接返回 └─ 未命中 ↓ 查询数据库 ↓ 写入一级缓存 ↓ 写入二级缓存提交后 ↓ 返回结果源码实现publicEListEquery(MappedStatementms,Objectparameter,...){BoundSqlboundSqlms.getBoundSql(parameter);CacheKeykeycreateCacheKey(ms,parameter,rowBounds,boundSql);// 步骤1查二级缓存Cachecachems.getCache();if(cache!nullms.isUseCache()){ListElist(ListE)tcm.getObject(cache,key);if(list!null){returnlist;// 二级缓存命中}}// 步骤2查一级缓存ListElist(ListE)localCache.getObject(key);if(list!null){returnlist;// 一级缓存命中}//步骤3查数据库listqueryFromDatabase(ms,parameter,...);//步骤4写入缓存localCache.putObject(key,list);if(cache!null){tcm.putObject(cache,key,list);}returnlist;}六、装饰器模式的运用MyBatis缓存的装饰器设计堪称经典让我们看看如何给缓存穿衣服。LruCache智能淘汰publicclassLruCacheimplementsCache{privatefinalCachedelegate;privateMapObject,ObjectkeyMap;// LinkedHashMap实现LRUprivateObjecteldestKey;OverridepublicObjectgetObject(Objectkey){keyMap.get(key);//访问即刷新顺序returndelegate.getObject(key);}OverridepublicvoidputObject(Objectkey,Objectvalue){delegate.putObject(key,value);cycleKeyList(key);//淘汰最久未用的}}ScheduledCache定时清理publicclassScheduledCacheimplementsCache{privatelongclearInterval3600000;// 1小时privatelonglastClear;OverridepublicObjectgetObject(Objectkey){if(System.currentTimeMillis()-lastClearclearInterval){clear();//时间到清空缓存returnnull;}returndelegate.getObject(key);}}SerializedCache深拷贝保护publicclassSerializedCacheimplementsCache{OverridepublicvoidputObject(Objectkey,Objectvalue){// 序列化存储delegate.putObject(key,serialize((Serializable)value));}OverridepublicObjectgetObject(Objectkey){// 反序列化返回每次都是新对象Objectobjectdelegate.getObject(key);returnobjectnull?null:deserialize((byte[])object);}}SynchronizedCache线程安全卫士publicclassSynchronizedCacheimplementsCache{OverridepublicsynchronizedvoidputObject(Objectkey,Objectvalue){delegate.putObject(key,value);}OverridepublicsynchronizedObjectgetObject(Objectkey){returndelegate.getObject(key);}}装饰器链的构建privateCachesetStandardDecorators(Cachecache){//按顺序穿衣服if(blocking){cachenewBlockingCache(cache);}if(readWrite){cachenewSerializedCache(cache);}if(scheduled){cachenewScheduledCache(cache);}if(logging){cachenewLoggingCache(cache);}if(sync){cachenewSynchronizedCache(cache);}//LRU通常是最外层cachenewLruCache(cache);returncache;}七、最佳实践推荐做法1.一级缓存- 保持默认开启适合单会话重复查询2.二级缓存- 仅在读多写少的场景开启3.LRU策略- 大多数场景的最佳选择4.合理设置容量- 根据业务量评估避免内存溢出5.只读缓存- 不可变对象使用readOnly“true”避免做法1.在频繁更新的表上开启二级缓存2.缓存大对象或包含敏感信息的对象3.忽略缓存带来的数据一致性问题4.不监控缓存命中率就盲目使用性能优化技巧热点数据优先合理设置TTL只读缓存加速监控命中率!--核心业务表单独配置--cache size2048evictionLRU/!--根据数据更新频率设置--cache flushInterval300000/!--5分钟--!--不可变数据使用只读缓存--cache readOnlytrue/!--开启日志记录--cacheproperty nameloggingvaluetrue//cache常见问题速查问题1二级缓存不生效!--解决方案--!--1.检查全局配置--settingssetting namecacheEnabledvaluetrue//settings!--2.检查Mapper配置--cache/!--3.确保实体类实现Serializable--publicclassUserimplementsSerializable{privatestaticfinallongserialVersionUID1L;}问题2数据不一致!--解决方案及时刷新缓存--update idupdateUserflushCachetrueUPDATE t_userSETname#{name}WHEREid#{id}/update!--或设置自动刷新--cache flushInterval60000/问题3内存溢出!--解决方案1限制容量--cache size512/!--解决方案2使用软引用--cache evictionSOFT/!--解决方案3定时清理--cache flushInterval3600000/实战案例场景电商系统商品查询优化mapper namespacecom.shop.mapper.ProductMapper!--商品信息变化不频繁适合二级缓存 使用LRU淘汰策略 设置1小时自动刷新 容量2048覆盖热门商品--cache evictionLRUflushInterval3600000size2048readOnlyfalse/select idselectByIdresultTypeProductSELECT*FROM t_productWHEREid#{id}/select!--更新操作强制刷新缓存--update idupdateProductflushCachetrueUPDATE t_productSETprice#{price}WHEREid#{id}/update/mapper八、总结一级缓存SqlSession级别默认开启增删改自动清空适合单会话重复查询二级缓存Mapper级别需手动配置跨SqlSession共享适合读多写少场景装饰器模式灵活组合功能支持多种淘汰策略可扩展自定义实现CacheKey机制多元素组成确保唯一性精确命中判断

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询