做简单网站怎么做广州物流网站开发

news/2025/10/3 11:55:31/文章来源:
做简单网站怎么做,广州物流网站开发,杭州网络安全公司,四川住房和城乡建设局网站首页前言 如果项目业务处于起步阶段#xff0c;流量非常小#xff0c;那无论是读请求还是写请求#xff0c;直接操作数据库即可#xff0c;这时架构模型是这样的#xff1a; 但随着业务量的增长#xff0c;项目业务请求量越来越大#xff0c;这时如果每次都从数据库中读数据…前言 如果项目业务处于起步阶段流量非常小那无论是读请求还是写请求直接操作数据库即可这时架构模型是这样的 但随着业务量的增长项目业务请求量越来越大这时如果每次都从数据库中读数据那肯定会有性能问题。这个阶段通常的做法是引入缓存来提高读性能架构模型就变成了这样 在实际开发过程中缓存的使用频率是非常高的只要使用缓存和数据库存储就难免会出现双写时数据一致性的问题就是 Redis 缓存的数据和数据库中保存的数据出现不相同的现象。 如上图所示大多数人的很多业务操作都是根据这个图来做缓存的这样能有效减轻数据库压力。但是一旦设计到双写或者数据库和缓存更新等操作就很容易出现数据一致性的问题。无论是先写数据库在删除缓存还是先删除缓存在写入数据库都会出现数据一致性的问题。例如 先删除了redis缓存但是因为其他什么原因还没来得及写入数据库另外一个线程就来读取发现缓存为空则去数据库读取到之前的数据并写入缓存此时缓存中为脏数据。如果先写入了数据库但是在缓存被删除前写入数据库的线程因为其他原因被中断了没有删除掉缓存就也会出现数据不一致的情况。 总的来说写和读在多数情况下都是并发的不能绝对保证先后顺序就会很容易出现缓存和数据库数据不一致的情况那我们又该如何解决呢 一、谈谈一致性 首先我们先来看看有哪几种一致性的情况呢 强一致性如果你的项目对缓存的要求是强一致性的那么请不要使用缓存。这种一致性级别是最符合用户直觉的它要求系统写入什么读出来的也会是什么用户体验好但实现起来往往对系统的性能影响大。读请求和写请求会串行化串到一个内存队列里去这样会大大增加系统的处理效率吞吐量也会大大降低。弱一致性这种一致性级别约束了系统在写入成功后不承诺立即可以读到写入的值也不承诺多久之后数据能够达到一致但会尽可能地保证到某个时间级别比如秒级别后数据能够达到一致状态。最终一致性最终一致性是弱一致性的一个特例系统会保证在一定时间内能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来是因为它是弱一致性中非常推崇的一种一致性模型也是业界在大型分布式系统的数据一致性上比较推崇的模型。一般情况下高可用只确保最终一致性不确保强一致性。 二、 情景分析 2.1 针对读场景 A请求查询数据如果命中缓存那么直接取缓存数据返回即可。如果请求中不存在数据库中存在那么直接取数据库数据返回然后将数据同步到Redis中。不会存在数据不一致的情况。 在高并发的情况下A请求和B请求一起访问某条数据如果缓存中数据存在直接返回即可如果不存在直接取数据库数据返回即可。无论A请求B请求谁先谁后本质上没有对数据进行修改数据本身没变只是从缓存中取还是从数据库中取的问题因此不会存在数据不一致的情况。 因此单独的读场景是不会造成Redis与数据库缓存不一致的情况因此我们不用关心这种情况。 2.2 针对写场景 如果该数据在缓存中不存在那么直接修改数据库中的数据即可不会存在数据不一致的情况。 如果该数据在缓存中和数据库中都存在那么就需要既修改缓存中的数据又修改数据库中的数据。如果写数据库的值与更新到缓存值是一样的可以马上更新缓存如果写数据库的值与更新缓存的值不一致在高并发的场景下还存在先后关系这就会导致数据不一致的问题。例如 当更新数据时如更新某商品的库存当前商品的库存是100现在要更新为99先更新数据库更改成99然后删除缓存发现删除缓存失败了这意味着数据库存的是99而缓存是100这导致数据库和缓存不一致。在高并发的情况下如果当删除完缓存的时候这时去更新数据库但还没有更新完另外一个请求来查询数据发现缓存里没有就去数据库里查还是以上面商品库存为例如果数据库中产品的库存是100那么查询到的库存是100然后插入缓存插入完缓存后原来那个更新数据库的线程把数据库更新为了99导致数据库与缓存不一致的情况。 三、同步策略 想要保证缓存与数据库的双写一致一共有4种方式即4种同步策略 从这4种同步策略中我们需要作出比较的是更新缓存与删除缓存哪种方式更合适应该先操作数据库还是先操作缓存 3.1 先更新缓存再更新数据库 这个方案我们一般不考虑。原因是当数据同步时更新 Redis 缓存成功但更新数据库出现异常时会导致 Redis 缓存数据与数据库数据完全不一致而且这很难察觉因为 Redis 缓存中的数据一直都存在。 只要缓存进行了更新后续的读请求基本上就不会出现缓存未命中的情况。但在某些业务场景下更新数据的成本较大并不是单纯将数据的数据查询出来丢到缓存中即可而是需要连接很多张表组装对应数据存入缓存中并且可能存在更新后该数据并不会被使用到的情况。 3.2 先更新数据库再更新缓存 这个方案我们一般也是不考虑。原因是当数据同步时数据库更新成功但 Redis 缓存更新失败那么此时数据库中是最新值Redis 缓存中是旧值。之后的应用系统的读请求读到的都是 Redis 缓存中旧数据。只有当 Redis 缓存数据失效后才能从数据库中重新获得正确的值。 该方案还存在并发引发的一致性问题假设同时有两个线程进行数据更新操作如下图所示 从上图可以看到线程1虽然先于线程2发生但线程2操作数据库和缓存的时间却要比线程1的时间短执行时序发生错乱最终这条数据结果是不符合预期的。如果是写多读少的场景采用这种方案就会导致数据压根还没读到缓存就被频繁的更新浪费性能。 3.3 先删除缓存后更新数据库 这种方案只是尽可能保证一致性而已极端情况下还是有可能发生数据不一致问题原因是当数据同步时如果删除 Redis 缓存失败更新数据库成功那么此时数据库中是最新值Redis 缓存中是旧值。之后的应用系统的读请求读到的都是 Redis 缓存中旧数据。只有当 Redis 缓存数据失效后才能从数据库中重新获得正确的值。由于缓存被删除下次查询无法命中缓存需要在查询后将数据写入缓存增加查询逻辑。同时在高并发的情况下同一时间大量请求访问该条数据第一条查询请求还未完成写入缓存操作时这种情况大量查询请求都会打到数据库加大数据库压力。 该方案还存在并发引发的一致性问题假设同时有两个线程进行数据更新操作如下图所示。当缓存被线程一删除后如果此时有新的读请求线程二发生由于缓存已经被删除这个读请求线程二将会去从数据库查询。如果此时线程一还没有修改完数据库线程二从数据库读的数据仍然是旧值同时线程二将读的旧值写入到缓存。线程一完成后数据库变为新值而缓存还是旧值。 从上图可见先删除 Redis 缓存后更新数据库当发生读/写并发时还是存在数据不一致的情况。如何解决呢最简单的解决办法就是延时双删策略先淘汰缓存、再写数据库、休眠后再次淘汰缓存。这样做的目的就是确保读请求结束写请求可以删除读请求造成的缓存脏数据。 public void deleteRedisData(UserInfo userInfo){// 删除Redis中的缓存数据jedis.del(userInfo);// 更新MySQL数据库数据userInfoDao.update(userInfo);try {TimeUnit.SECONDS.sleep(2);} catch(Exception exp){exp.printStackTrace();}// 删除Redis中的缓存数据jedis.del(userInfo); }延时双删就能彻底解决不一致吗当然不一定来。首先我们评估的延时时间并不能完全代表实际运行过程中的耗时运行过程如果因为系统压力过大我们评估的耗时就是不准确仍然会导致数据不一致的出现。其次延时双删虽然在保证事务提交完以后再进行删除缓存但是如果使用的是MySQL的读写分离的机构主从同步之间其实也会有时间差。 3.4 先更新数据库后删除缓存 实际使用中建议采用这种方案。当然这种方案其实一样也可能有失败的情况。 当数据同步时如果更新数据库成功而删除 Redis 缓存失败那么此时数据库中是最新值Redis 缓存中是旧值。之后的应用系统的读请求读到的都是 Redis 缓存中旧数据。只有当 Redis 缓存数据失效后才能从数据库中重新获得正确的值。读的时候先读缓存缓存没有的话就读数据库然后取出数据后放入缓存同时返回响应。更新的时候先更新数据库然后再删除缓存。 该方案还存在并发引发的一致性问题假设同时有两个线程进行数据更新操作如下图所示。当数据库的数据被更新后如果此时缓存还没有被删除那么缓存中的数据仍然是旧值。如果此时有新的读请求查询数据发生由于缓存中的数据是旧值这个读请求将会获取到旧值。当缓存刚好失效这时有请求来读缓存线程一未命中缓存然后到数据库中读取在要写入缓存时线程二来修改了数据库而线程一写入缓存的是旧的数据导致了数据的不一致。 四、解决办法 当我们在应用中同时使用MySQL和Redis时如何保证两者的数据一致性呢下面就来分享几种实用的解决方案。 4.1 双写一致性 最直接的办法就是在业务代码中同时对MySQL和Redis进行更新。通常我们会先更新MySQL然后再更新Redis。 // 更新MySQL userMapper.update(user); // 更新Redis redisTemplate.opsForValue().set(user_ user.getId(), user);这种方式最大的问题就是在于网络故障或者程序异常的情况下可能会导致MySQL和Redis中的数据不一致。因此我们需要额外的手段来检测和修复数据不一致的情况。 4.2 异步更新(异步通知) 在更新数据库数据时同时发送一个异步通知给Redis让Redis知道数据库数据已经更新需要更新缓存中的数据。这个过程是异步的不会阻塞数据库的更新操作。当Redis收到异步通知后会立即删除缓存中对应的数据确保缓存中没有旧数据。这样即使在这个过程中有新的读请求发生也不会读取到旧数据。等到数据库更新完成后Redis再次从数据库中读取最新的数据并缓存起来。 // 更新MySQL userMapper.update(user); // 发送消息 rabbitTemplate.convertAndSend(updateUser, user.getId());/*** 然后在消息消费者中更新Redis。*/ RabbitListener(queues updateUser) public void updateUser(String userId) {User user userMapper.selectById(userId);redisTemplate.opsForValue().set(redisTemplate.opsForValue().set(user_ user.getId(), user); }这种异步通知的方式可以确保Redis中的数据与数据库中的数据保持一致避免出现数据不一致的情况。这种方案可以降低数据不一致的风险但仍然无法完全避免。因为消息队列本身也可能因为各种原因丢失消息。 4.3 使用Redis的事务支持 Redis提供了事务Transaction支持可以将一系列的操作作为一个原子操作执行。我们可以利用Redis的事务来实现MySQL和Redis的原子更新。 redisTemplate.execute(new SessioncallbackObject(){0verridepublic Object execute(RedisOperations operations) throws DataAccessException {// 开启事务operations.multi();// 更新MySQLuserMapper.update(user);// 更新Redisoperations.opsForValue().set(user_ user.getId(),user);// 执行事务operations.exec();return null;} });使用Redis事务可以确保MySQL和Redis的更新在同一事务中执行避免了中间出现不一致的情况。但需要注意的是Redis的事务并非严格的ACID事务可能存在部分成功的情况。 4.4 用 Redisson 实现读锁和写锁 Redisson 是一个基于 Redis 的分布式 Java 对象存储和缓存框架它提供了丰富的功能和 API 来操作 Redis 数据库其中包括了读写锁的支持。读写锁是一种常用的并发控制机制它允许多个线程同时读取共享资源但在写操作时互斥只允许一个线程进行写操作。使用 Redisson 的读写锁方法 获取读锁通过 Redisson 的 RReadWriteLock 对象的 readLock() 方法获取读锁。在获取读锁后可以并发读取共享资源不会阻塞其他获取读锁的线程。获取写锁通过 Redisson 的 RReadWriteLock 对象的 writeLock() 方法获取写锁。在获取写锁后其他获取读锁和写锁的线程将被阻塞只有当前线程能够进行写操作。释放锁使用完读锁或写锁后应该及时调用 unlock() 方法释放锁以便其他线程可以获取锁并进行操作。在 Redisson 中读锁和写锁都继承自锁对象 RLock因此可以使用 RLock 的 unlock() 方法来释放锁。 下面是一个使用 Redisson 读写锁的示例通过 Redisson 的 RReadWriteLock 对象获取读锁和写锁并在需要的代码段中进行相应的操作。执行完操作后使用 unlock() 方法释放锁最后关闭 Redisson 客户端。 import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config;public class RedissonReadWriteLockExample {public static void main(String[] args) {// 创建 Redisson 客户端Config config new Config();config.useSingleServer().setAddress(redis://127.0.0.1:6379);RedissonClient redisson Redisson.create(config);// 获取读写锁RReadWriteLock rwLock redisson.getReadWriteLock(myLock);RLock readLock rwLock.readLock();RLock writeLock rwLock.writeLock();try {// 获取读锁并进行读操作readLock.lock();// 读取共享资源// 获取写锁并进行写操作writeLock.lock();// 写入共享资源} finally {// 释放锁writeLock.unlock();readLock.unlock();}// 关闭 Redisson 客户端redisson.shutdown();} }五、结语 综上所述我们提供了更全面的MySQL与Redis数据一致性解决方案。根据具体的业务需求和系统环境选择合适的方案可以提高数据一致性的可靠性。然而每种方案都有其优缺点和适用场景需要综合考虑权衡。 对于并发几率很小的数据(如个人维度的订单数据、用户数据等)这种几乎不用考虑这个问题很少会发生缓存不一致可以给缓存数据加上过期时间每隔一段时间触发读的主动更新即可。就算并发很高如果业务上能容忍短时间的缓存数据不一致(如商品名称商品分类菜单等)缓存加上过期时间依然可以解决大部分业务对于缓存的要求。 把今天最好的表现当作明天最新的起点…..

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/925858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年防撞软包厂家TOP企业品牌推荐排行榜,谈话室,留置病房,教育中心,体育馆,约谈室,监察机构,墙体,阻燃,醒酒室,墙面,洽谈室,留置室,防撞软包洽谈桌公司推荐

引言在公检法审讯室、留置室等特殊场所,以及幼儿园、办公空间等场景中,防撞软包作为保障安全、优化环境的关键材料,其市场需求持续攀升。但当前行业却面临诸多乱象:部分产品环保不达标,存在有毒有害物质挥发,长期…

合肥市建设行政主管部门网站网页被禁止浏览怎么解决

问题描述 如上图所示,最近在学习C#突然发现我在运行Hello World的时候出现这样的乱码情况。 分析原因 主要是因为VS Code 是UTF-8的编码格式,而我们的PC是Unicode编码,所以我们需要对其进行一个统一即可解决问题。那么知道这个的问题那就开…

MySQL 全量 + 增量备份脚本(RPM 安装)实践与疑问解析

MySQL 全量 + 增量备份脚本(RPM 安装)实践与疑问解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

2025最新展会搭建公司推荐排行榜:服务商创意定制与全流程服务能力深度解析

会展经济的蓬勃发展让展会搭建成为品牌展示的核心载体,但其行业痛点却日益凸显:多数服务商设计同质化严重,难以匹配品牌个性化表达;施工团队专业度参差不齐,进度延误与安全隐患屡见不鲜;服务链条断裂导致客户需多…

10 3

10.3P2679很容易想到定义状态 \(f_{i,j,k}\) 表示匹配到了 s 的第 \(i\) 个字符,t 的第 \(j\) 个字符用了 \(k\) 个串的方案数 然后你就会发现爆空间了 这时候我们可以使用滚动数组滚动第一维,令 \(f_{i,j,0/1}\) 表…

2025磁选机厂家TOP企业品牌推荐排行榜,立环磁选机,高梯度磁选机,立环高梯度磁选机,油冷立环磁选机公司推荐

在矿产加工与原料提纯行业中,磁选机作为核心分选设备,其品质与适配性直接影响生产效率与产品纯度。当前市场上,设备品牌繁杂、型号混乱,部分厂家存在产品单一、适配性不足等问题,难以满足不同规模企业的产能需求。…

医疗设备厂家不要再盲选了,专业的医疗DMS经销商管理软件来了!

当销售渠道遍地开花,管理却漏洞百出——是时候告别“盲选”,拥抱精准掌控!医疗设备厂家渠道管理中的挑战 在医疗器械行业深耕多年的厂家,你是否正被这些问题困扰:订单混乱效率低:手工处理订单慢、易出错,发货延…

做微商网站制作工作证明模板 范本

一、 could not establish connection to “XXX” 尝试使用Remote-SSH插件连接远程的服务器,但是配置显示出错,端口显示试图写入的管道不存在,弹出窗口显示could not establish connection to “XXX” 二、检查Windows的OpenSSH 1.检索是否…

修改网站空间服务器密码动态h5网站开发

安装情况: 直接安装提示错误!!! 安装程序命令: apt install -y docker.io 安装结果提示安装失败!!!看别人安装直接成功到我这怎么失败!!!找原因…

网站设计 上海医疗 网站前置审批

解决最短路径问题:(如下三种算法)(1)迪杰斯特拉算法(Dijkstra算法)(2)弗洛伊德算法(Floyd算法)(3)SPFA算法第一种算法:Dijkstra算法广度优先搜索解决赋权有向图或者无向图的单源最短路径问题.是一种贪心的策略算法的思路声明一个数组dis来保存源点到各个…

15年做哪个网站致富wordpress看不到图片

目的:将遥感图像进行地理配准、矢量化,并且制作地图。要求:对的遥感图像进行地理配准;矢量化建筑物、绿地、道路、水体等主要地物要素;对各类地物要素进行符号化设置并对其名称进行标注;添加指北针、比例尺…

2025最新编织袋生产厂家推荐排行榜:涵盖牛皮纸、塑料、PP 彩膜等品类,助力企业精准甄选可靠合作伙伴

在工业、农业、食品等领域的生产流转中,编织袋作为关键包装载体,其品质与供应稳定性直接关系到企业成本控制、产品安全及市场口碑。当前市场上编织袋生产厂家数量繁杂,部分厂家存在质量管理缺失、工艺水平落后、供货…

AT_abc266_g [ABC266G] Yet Another RGB Sequence

首先将 \(r, g\) 给捆绑出来,先把 \(g, b, rg\) 这三种东西给排好,方案数容易计算。 然后考虑到目前插板,不能将 \(r\) 插到 \(g\) 前面,空隙数是好计算的,于是简单组合一下就做完了。

2025超市货架厂家 TOP 企业品牌推荐排行榜,云南超市货架,昆明超市货架,西南超市货架推荐这十家公司!

引言在商超零售与专业门店的运营体系中,货架作为核心陈列与存储设备,其品质、设计适配性及服务效率,直接影响终端的空间利用率、顾客购物体验与长期运营成本。当前市场上,超市货架供给方数量众多,但质量参差不齐:…

详细介绍:鸿蒙与iOS跨平台开发方案全解析

详细介绍:鸿蒙与iOS跨平台开发方案全解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

US$58 HU162T Clamp Work on VW SN-CP-JJ-16 Work with SEC-E9 Key Cutting Machine

HU162T Clamp Work on VW SN-CP-JJ-16 Work with SEC-E9 Key Cutting MachineFor Volkswagen Golf 7, Magotan 2018, Lavida 2018, Phaeton etc. also for Audi 2018 new modelsPackage List:1pc* HU162T Clamp for VW…

17zwd一起做网站网站建设需要注意哪些方面

现在的猫咪主人都把自家的小猫当成了心头的宝贝,呵护备至。但宠爱过度有时会导致猫咪形成挑食的坏习惯。小猫挑食不吃猫粮是为什么呢?面对这一问题,我们应该如何解决呢? 今天,我给大家剖析一下小猫挑食不吃猫粮是为什…

完整教程:Linux中安装es

完整教程:Linux中安装es2025-10-03 11:33 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fo…

深入解析:Visual RM 用智能引擎重塑企业协作新模式!

深入解析:Visual RM 用智能引擎重塑企业协作新模式!pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&qu…

学习unigui【36】把数据导航放在Unidbgrid脚中

学习unigui【36】把数据导航放在Unidbgrid脚中UniDBGrid1.WebOptions.Paged := True;UniDBGrid1.PagingBarAuxControl := UniDBNavigator1;