学习搭建网站404做的好的网站

张小明 2025/12/30 23:49:01
学习搭建网站,404做的好的网站,wordpress免费建设,网站建设上市公司引言在现代Web应用中#xff0c;数据库访问往往是性能瓶颈之一。MyBatis作为流行的持久层框架#xff0c;其缓存机制是提升应用性能的关键特性。理解MyBatis的一二级缓存不仅有助于优化应用性能#xff0c;还能避免因缓存不当导致的数据一致性问题。本文将从基础概念到高级原…引言在现代Web应用中数据库访问往往是性能瓶颈之一。MyBatis作为流行的持久层框架其缓存机制是提升应用性能的关键特性。理解MyBatis的一二级缓存不仅有助于优化应用性能还能避免因缓存不当导致的数据一致性问题。本文将从基础概念到高级原理全方位解析MyBatis缓存机制。一、缓存的基本概念为什么需要缓存1.1 缓存的价值想象一下如果你每次需要知道时间都去天文台查询效率会很低。相反看一眼手表缓存就能立即获取时间。MyBatis缓存扮演的就是这个“手表”的角色它避免了频繁访问数据库天文台极大提升了查询效率。1.2 缓存的经济学原理时间局部性刚被访问的数据很可能再次被访问空间局部性相邻的数据很可能被一起访问访问成本内存访问纳秒级vs 磁盘/网络访问毫秒级二、一级缓存SqlSession级别的缓存2.1 什么是SqlSession在深入一级缓存前需要先理解SqlSession。SqlSession不是数据库连接Connection而是一次数据库对话的抽象// SqlSession相当于一次完整对话不是一通电话 SqlSession session sqlSessionFactory.openSession(); try { // 对话中的多次查询 userMapper.getUser(1); // 第一次查询 orderMapper.getOrders(1); // 第二次查询 accountMapper.getBalance(1); // 第三次查询 session.commit(); // 确认对话内容 } finally { session.close(); // 结束对话 }2.2 一级缓存的核心特性作用范围SqlSession内部一次对话默认状态自动开启无法关闭生命周期随SqlSession创建而创建随其关闭而销毁2.3 一级缓存的工作原理// 示例代码展示一级缓存行为 public void demonstrateLevel1Cache() { SqlSession session sqlSessionFactory.openSession(); UserMapper mapper session.getMapper(UserMapper.class); System.out.println(第一次查询用户1:); User user1 mapper.selectById(1); // 发SQLSELECT * FROM user WHERE id1 System.out.println(第二次查询用户1:); User user2 mapper.selectById(1); // 不发SQL从一级缓存读取 System.out.println(查询用户2:); User user3 mapper.selectById(2); // 发SQL参数不同缓存未命中 System.out.println(修改用户1:); mapper.updateUser(user1); // 清空一级缓存 System.out.println(再次查询用户1:); User user4 mapper.selectById(1); // 发SQL缓存被清空 session.close(); }2.4 一级缓存的数据结构一级缓存的实现非常简单直接// 一级缓存的核心实现类 public class PerpetualCache implements Cache { // 核心就是一个ConcurrentHashMap private final MapObject, Object cache new ConcurrentHashMap(); Override public void putObject(Object key, Object value) { cache.put(key, value); // 简单的Map.put() } Override public Object getObject(Object key) { return cache.get(key); // 简单的Map.get() } }缓存Key的生成规则// CacheKey包含以下要素决定两个查询是否相同 // 1. Mapper Idnamespace method // 2. 分页参数offset, limit // 3. SQL语句 // 4. 参数值 // 5. 环境Id // 这意味着即使SQL相同参数不同也会生成不同的CacheKey2.5 一级缓存的失效场景执行任何UPDATE/INSERT/DELETE操作手动调用clearCache()设置flushCachetrueSqlSession关闭查询参数变化因为CacheKey不同三、二级缓存Mapper级别的全局缓存3.1 二级缓存的核心特性作用范围Mapper级别跨SqlSession共享默认状态默认关闭需要手动开启生命周期随应用运行而存在3.2 二级缓存的配置!-- 1. 全局配置开启二级缓存 -- settings setting namecacheEnabled valuetrue/ /settings !-- 2. Mapper XML中配置 -- mapper namespacecom.example.UserMapper !-- 基本配置 -- cache/ !-- 详细配置 -- cache evictionLRU !-- 淘汰策略 -- flushInterval60000 !-- 刷新间隔毫秒 -- size1024 !-- 缓存对象数 -- readOnlytrue !-- 是否只读 -- blockingfalse/ !-- 是否阻塞 -- /mapper !-- 3. 在具体查询上使用缓存 -- select idselectById resultTypeUser useCachetrue SELECT * FROM user WHERE id #{id} /select !-- 4. 增删改操作刷新缓存 -- update idupdateUser flushCachetrue UPDATE user SET name #{name} WHERE id #{id} /update3.3 二级缓存的数据结构二级缓存不像一级缓存那么简单它采用了装饰器模式二级缓存装饰器链层层包装 ┌─────────────────────────┐ │ SerializedCache │ ← 序列化存储 │ LoggingCache │ ← 日志统计 │ SynchronizedCache │ ← 线程安全 │ LruCache │ ← LRU淘汰 │ PerpetualCache │ ← 基础HashMap └─────────────────────────┘每个装饰器都有特定功能PerpetualCache基础存储使用HashMapLruCache最近最少使用淘汰SynchronizedCache保证线程安全LoggingCache记录命中率SerializedCache序列化对象防止修改3.4 二级缓存的工作流程public void demonstrateLevel2Cache() { // 用户A查询第一个访问者 SqlSession sessionA sqlSessionFactory.openSession(); UserMapper mapperA sessionA.getMapper(UserMapper.class); User user1 mapperA.selectById(1); // 查询数据库 sessionA.close(); // 关键关闭时才会写入二级缓存 // 用户B查询不同SqlSession SqlSession sessionB sqlSessionFactory.openSession(); UserMapper mapperB sessionB.getMapper(UserMapper.class); User user2 mapperB.selectById(1); // 从二级缓存读取不发SQL // 管理员更新数据 SqlSession sessionC sqlSessionFactory.openSession(); UserMapper mapperC sessionC.getMapper(UserMapper.class); mapperC.updateUser(user1); // 清空相关二级缓存 sessionC.commit(); sessionC.close(); // 用户D再次查询 SqlSession sessionD sqlSessionFactory.openSession(); UserMapper mapperD sessionD.getMapper(UserMapper.class); User user3 mapperD.selectById(1); // 缓存被清重新查询数据库 sessionD.close(); }3.5 二级缓存的同步机制二级缓存有一个重要特性事务提交后才更新。这意味着// 场景事务内查询事务提交前其他会话看不到更新 SqlSession session1 sqlSessionFactory.openSession(); UserMapper mapper1 session1.getMapper(UserMapper.class); // 修改数据但未提交 mapper1.updateUser(user); // 此时二级缓存还未更新 // 另一个会话查询 SqlSession session2 sqlSessionFactory.openSession(); UserMapper mapper2 session2.getMapper(UserMapper.class); User user2 mapper2.selectById(1); // 可能读到旧数据 session1.commit(); // 提交后二级缓存才会更新 // 之后的新查询才会看到新数据四、一二级缓存的对比与选择4.1 核心差异对比特性一级缓存二级缓存作用范围SqlSession内部Mapper级别跨SqlSession默认状态开启关闭数据结构简单HashMap装饰器链共享性私有不共享公共所有会话共享生命周期随SqlSession创建销毁随应用运行持久存在性能影响极小内存访问中等可能有序列化开销适用场景会话内重复查询跨会话共享查询4.2 生活化比喻一级缓存私人对话记忆你和朋友的聊天内容只有你们两人知道聊天结束SqlSession关闭记忆逐渐模糊二级缓存公司公告栏重要通知写在公告栏所有员工都能看到通知更新时需要擦掉旧的写上新的公告栏内容持久存在直到被更新4.3 使用场景建议适合一级缓存的场景// 场景1方法内多次查询相同数据 public void processOrder(Long orderId) { Order order1 validateOrder(orderId); // 第一次查数据库 Order order2 calculateDiscount(orderId); // 走一级缓存 Order order3 generateInvoice(orderId); // 走一级缓存 } // 场景2循环内查询 for (int i 0; i 100; i) { Config config configMapper.getConfig(system_timeout); // 只有第一次查数据库后续99次走缓存 }适合二级缓存的场景// 场景1读多写少的配置数据 SystemConfig config configMapper.getConfig(app_settings); // 多个用户频繁读取很少修改 // 场景2热门商品信息 Product product productMapper.getHotProduct(666); // 商品详情页大量用户访问同一商品 // 场景3静态字典数据 ListCity cities addressMapper.getAllCities(); // 城市列表很少变化不适合缓存的场景// 场景1实时性要求高的数据 Stock stock stockMapper.getRealTimeStock(productId); // 库存信息需要实时准确 // 场景2频繁更新的数据 UserBalance balance accountMapper.getBalance(userId); // 用户余额每次交易都变化 // 场景3大数据量查询 ListLog logs logMapper.getTodayLogs(); // 数据量大缓存占用内存过多五、缓存的高级特性与原理5.1 缓存淘汰策略MyBatis提供了多种淘汰策略cache eviction策略类型 size缓存大小可用策略LRULeast Recently Used最近最少使用默认FIFOFirst In First Out先进先出SOFT软引用内存不足时被GC回收WEAK弱引用GC时立即回收5.2 LRU缓存的实现原理public class LruCache implements Cache { private final Cache delegate; // 使用LinkedHashMap实现LRU private MapObject, Object keyMap; private Object eldestKey; public void setSize(final int size) { keyMap new LinkedHashMapObject, Object(size, .75F, true) { Override protected boolean removeEldestEntry(Map.EntryObject, Object eldest) { boolean tooBig size() size; if (tooBig) { eldestKey eldest.getKey(); } return tooBig; } }; } Override public Object getObject(Object key) { // 访问时更新顺序 keyMap.get(key); return delegate.getObject(key); } }5.3 缓存查询的完整流程查询执行流程 1. 请求到达CachingExecutor二级缓存入口 2. 生成CacheKey包含SQL、参数等信息 3. 查询二级缓存 └─ 命中 → 返回结果 └─ 未命中 → 继续 4. 查询一级缓存 └─ 命中 → 返回结果并放入二级缓存事务提交时 └─ 未命中 → 继续 5. 查询数据库 6. 结果存入一级缓存 7. 事务提交时一级缓存刷入二级缓存 8. 返回结果六、缓存的最佳实践与避坑指南6.1 最佳实践1. 合理配置缓存大小!-- 根据数据特点设置合适的大小 -- cache size1024/ !-- 缓存1024个对象 --2. 设置合理的刷新间隔!-- 对于变化不频繁但需要定期更新的数据 -- cache flushInterval1800000/ !-- 30分钟自动刷新 --3. 选择性使用缓存!-- 某些查询跳过缓存 -- select idgetRealTimeData useCachefalse SELECT * FROM realtime_table /select !-- 某些查询强制刷新缓存 -- select idgetImportantData flushCachetrue SELECT * FROM important_table /select4. 关联查询的缓存策略!-- 关联查询时使用cache-ref同步缓存 -- mapper namespacecom.example.UserMapper cache/ !-- 其他配置 -- /mapper mapper namespacecom.example.OrderMapper !-- 引用UserMapper的缓存 -- cache-ref namespacecom.example.UserMapper/ /mapper6.2 常见问题与解决方案问题1脏读问题场景一个会话修改数据但未提交另一个会话从二级缓存读取到旧数据。解决方案// 设置事务隔离级别 Transactional(isolation Isolation.READ_COMMITTED) public void updateUser(User user) { userMapper.updateUser(user); } // 或者在Mapper中设置flushCache Update(UPDATE user SET name#{name} WHERE id#{id}) Options(flushCache Options.FlushCachePolicy.TRUE) int updateUser(User user);问题2内存溢出场景缓存大量数据导致JVM内存不足。解决方案设置合理的缓存大小和淘汰策略使用软引用/弱引用缓存定期清理不活跃的缓存问题3分布式环境缓存不一致场景多台服务器每台有自己的缓存数据不一致。解决方案使用集中式缓存Redis、Memcached替代默认二级缓存实现自定义Cache接口public class RedisCache implements Cache { private JedisPool jedisPool; Override public void putObject(Object key, Object value) { try (Jedis jedis jedisPool.getResource()) { jedis.set(serialize(key), serialize(value)); } } Override public Object getObject(Object key) { try (Jedis jedis jedisPool.getResource()) { byte[] value jedis.get(serialize(key)); return deserialize(value); } } }问题4缓存穿透场景查询不存在的数据每次都查数据库。解决方案// 缓存空对象 public User getUser(Long id) { User user userMapper.selectById(id); if (user null) { // 缓存空值设置短过期时间 cacheNullValue(id); return null; } return user; }6.3 监控与调试开启缓存日志# 查看缓存命中情况 logging.level.org.mybatisDEBUG logging.level.com.example.mapperTRACE监控缓存命中率// 获取缓存统计信息 Cache cache sqlSession.getConfiguration() .getCache(com.example.UserMapper); if (cache instanceof LoggingCache) { LoggingCache loggingCache (LoggingCache) cache; System.out.println(命中次数: loggingCache.getHitCount()); System.out.println(未命中次数: loggingCache.getMissCount()); System.out.println(命中率: (loggingCache.getHitCount() * 100.0 / (loggingCache.getHitCount() loggingCache.getMissCount())) %); }七、总结与思考7.1 核心要点回顾一级缓存SqlSession级别自动开启基于HashMap简单高效二级缓存Mapper级别需手动开启基于装饰器模式功能丰富缓存Key由SQL、参数等要素生成决定查询是否相同事务同步二级缓存在事务提交后才更新避免脏读适用场景根据数据特点选择合适的缓存策略7.2 设计思想启示MyBatis缓存设计体现了几个重要软件设计原则单一职责原则每个缓存装饰器只负责一个功能开闭原则通过装饰器模式无需修改原有代码即可扩展功能接口隔离Cache接口定义清晰便于自定义实现7.3 实际应用建议在实际项目中从小开始先使用一级缓存确有需要再开启二级缓存测试验证上线前充分测试缓存效果和内存占用监控调整生产环境监控缓存命中率根据实际情况调整配置文档记录记录缓存配置和策略便于团队协作和维护7.4 未来展望随着微服务和云原生架构的普及MyBatis缓存也在演进分布式缓存集成更好支持Redis等分布式缓存多级缓存策略本地缓存分布式缓存的组合使用智能缓存管理基于访问模式的自动缓存优化结语MyBatis缓存机制是一个看似简单实则精妙的设计。理解它不仅能帮助我们优化应用性能还能加深对缓存设计模式的理解。记住缓存是提升性能的利器但也可能成为数据一致的陷阱。合理使用、谨慎配置、持续监控才能让缓存真正为应用赋能。缓存不是银弹而是需要精心调校的利器。在实际开发中应根据业务特点、数据特性和访问模式选择最合适的缓存策略在性能与一致性之间找到最佳平衡点。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站改版建设征求意见书分销系统模式

1、--collect-only查看在给定的配置下哪些测试用例会被执行2、-k使用表达式来指定希望运行的测试用例。如果测试名是唯一的或者多个测试名的前缀或者后缀相同,可以使用表达式来快速定位,例如:命令行-k参数.png3、-m标记(marker&am…

张小明 2025/12/29 3:53:36 网站建设

判断网站模板版本网站底部版权代码

NVIDIA Profile Inspector配置保存失败的深度排查指南 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 故障现象快速识别 当你点击NVIDIA Profile Inspector的"Apply changes"按钮时&#xf…

张小明 2025/12/28 16:50:11 网站建设

万网 网站建设方案书范文seo公司系统

MT3音乐转录:用AI技术让音频秒变乐谱的完整指南 【免费下载链接】mt3 MT3: Multi-Task Multitrack Music Transcription 项目地址: https://gitcode.com/gh_mirrors/mt/mt3 你是否曾梦想过将听到的音乐瞬间转换为乐谱?MT3音乐转录模型让这个梦想成…

张小明 2025/12/29 7:41:58 网站建设

网站建设代理招标如何给wordpress添加一张网站背景

Kazumi智能同步:重塑你的跨设备观影连续性体验 【免费下载链接】Kazumi 基于自定义规则的番剧采集APP,支持流媒体在线观看,支持弹幕。 项目地址: https://gitcode.com/gh_mirrors/ka/Kazumi 在数字娱乐时代,我们的观影场景…

张小明 2025/12/28 19:36:14 网站建设

在网站上做教育直播平台多少钱神马搜索推广

树莓派的远程打印服务器与电话系统搭建指南 1. 树莓派作为远程打印服务器 当我们想要打印文件时,往往不在连接着笨重、难看打印机的那台电脑旁边。树莓派体积小巧,我们可以把打印机藏在任何地方,让树莓派充当打印服务器来完成打印工作。 1.1 安装 CUPS 将树莓派变成打印…

张小明 2025/12/28 23:07:23 网站建设

网站推广联系磁遁8刺盾云帝国cms地方门户网站模板

目录已开发项目效果实现截图开发技术系统开发工具:核心代码参考示例1.建立用户稀疏矩阵,用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式&…

张小明 2025/12/29 4:55:16 网站建设