电子商务网站建设与管理学习心得,爱站网官网,南昌网站排名优化费用,南昌房产网官方网站业务的流程大概就是#xff0c;先判断优惠卷是否过期#xff0c;然后判断是否有库存#xff0c;最好进行扣减库存#xff0c;加入全局唯一id#xff0c;然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题#xff0c;比如开200个线程进行抢购#xff0c;抢100个… 业务的流程大概就是先判断优惠卷是否过期然后判断是否有库存最好进行扣减库存加入全局唯一id然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题比如开200个线程进行抢购抢100个商品最后发现生产力109个订单库存发现是-9这就出现了超卖问题。 这个是怎么出现的呢比如我现在判断库存为1那么我开始扣减库存此时还没扣减的时候线程二来发现库存还是大于0那么我线程2也开始扣减库存此时线程一和线程二都执行扣减就导致库存从1变为-1 有两种解决方案悲观锁和乐观锁悲观锁就是用lock 或者 synchronized让所有线程变成串行方式执行乐观锁是判断之前查到的数据是否被修改了如果被修改了就不允许下一步操作重新获取最新的数据进行操作。 乐观锁版本号法设置版本号每次进行减库存的时候都要进行版本1。大概流程是这样的先进行查询版本号1库存1然后线程二进来了同样查询库存1版本号1然后线程1开始判断版本号是否等于之前查出来的版本号1如果相等就更新并且版本1。然后线程二在进行判断此时判断版本号与自己线程当前查出的版本号不一致1≠2了此时更新失败。 简化玩法通过数据业务本身进行判断原本数据是否有变化例如查出库存然后扣减库存的时候如果发现库存与查出的库存不一致说明期间有线程将库存修改那么就修改失败。
二、一人一单问题 同一个优惠卷一个只能抢一次。在多线程情况下可能会出现一个人强好几次都抢到了的情况。这和之前超卖问题差不多都是第一次检查自己有没有抢购这个优惠卷的时候判断认为自己没有抢过此时其他线程进来也查数据库也没有所以会同时新增优惠卷抢购订单。但由于之前的超卖是修改的问题而这个是新增的问题所以不太好用乐观锁。 可以用悲观锁先获取用户的id根据用户id获取锁提交事务然后释放锁因为不同用户可以同时操作 但是同一个用户只能串行执行避免并发问题。 三、集群模式下一人一单问题 对于多集群下服务器有多个可能用户会访问不同的服务器假如在抢优惠卷的时候分别发送了两个请求访问然后分别发送请求到两台服务器那么每台服务器的Tomcat不同jvm也就不同那么他们获取的锁对象也是不同的所以同一个用户在这种情况下用synchronized是锁不住的。 解决方案使用分布式锁 分布式锁 必须满足在多集群多线程下多进程可见并且互斥。mysql性能一般安全性可以高可用还可以可以理由x锁锁住某条数据进行作为全局锁然后通过报异常回滚释放锁。然后用redis的话效率高高可用可以拓展主从机制使用SETNX完成互斥。 使用redis方式来实现分布式锁。 代码实现 setIfAbsent就相当于NX然后时间是EX设置超时时间目的是为了宕机或者卡主锁不释放的情况。 锁的误删问题 线程1在业务过程中卡住了对应的锁因为时间太长锁失效了删除了此时业务二进来获取锁那么获取成功在正常业务过程中业务一恢复正常然后快结束的时候将锁释放此时会把业务二中拿到的锁给释放掉。 解决方法就是在获取锁的时候要存入线程id释放锁的时候判断锁的线程id是不是自己的是自己的才能释放确保锁不会误删。 但是极端的情况下还会有锁的误删问题比如在业务获取锁执行完毕之后在进行判断是否是自己当前线程的锁如果是那么此时突然阻塞等下一个线程进行业务过程中获取锁然后执行一般的时候线程一恢复正常他会进行释放锁因为在阻塞之前进行过判断是否是当前线程此时只执行释放锁的操作那么依然会将就锁删除掉。 解决方法 要保证 判断是否是当前锁已经释放锁的过程是原子性的要一块进行操作。我们可以用lua脚本在里面执行redis的操作要么都执行成功要么都失败。 在以上这些锁有一个问题就是不可重入不可重试超时释放主从一致性用主节点加了一个锁但是主从未同步完成的时候主节点挂了那么此时其他线程又要获取锁发现从节点没有锁标志那么就会出现同一把锁获取两次不同线程的问题。 使用Redisson解决 Redisson实现可重入锁原理 是一个hash结构key是锁的名字对应的键值对的key是锁的线程的idvalue是锁的使用次数如果不存在就正常加锁默认是value的value是1所以如果解锁就将这个值-1判断为0就释放锁如果是重入的话会判断这个锁是不是当前线程的如果是的话就会将锁的value的value1直到将锁逐层释放等到value的value为0时才释放。这些操作实际上是写在lua脚本里保证原子性。 Redisson实现锁的可重试超时效 首先会获取锁判断锁是否存在如果不存在就获取成功如果手动设置了超时时间就直接结束。如果没有设置超时时间看门狗会一直重复续约超时时间默认是30秒然后30/3每隔10秒续约10秒一直往目的是防止业务还没完成就自动释放锁。然后当时判断锁存在那么会判断锁的时间还有吗没有的话直接结束如果有的话会有信号量机制订阅信息等待锁的释放如果收到锁释放的信息那么它会再次判断是否超时如果超时了结束如果没超时重新获取一遍锁。如果锁释放成功会取消看门狗因为业务结束会释放锁所以意味着业务结束。 Redisson实现锁的主从一致性。 它实现的方法就是比如有三个节点每次加锁必须将三个节点都加上锁才叫获取锁成功以此为依据。假设这三个节点有对应的从节点假设其中有一个主节点崩溃从节点作为主节点此时如果主从没有及时更新那么从节点作为主节点发现没有锁的表示而其他两个阶段是正常的有锁的表示此时如果有个线程趁虚而入想获取锁此时只有第一个节点能获取锁其他两个节点由于之前加了锁了所以不能获取到锁所以加锁失败。