订单业务中的重要问题:超卖问题的解决方案

2023-11-06

订单业务中的重要问题:超卖问题的解决方案

我在做过的一些项目中都涉及到了订单的业务,如果你的项目中有关于订单的业务模块,那肯定说明你的项目中有卖商品的功能,所以有买卖场景就面临一个很常见的一个问题,那就是超卖问题,下面我就整理一下我在做项目的时候使用的一种很好用的解决方案来避免出现超卖问题。

什么是超卖问题,以及超卖问题是如何产生的?

超卖问题,通俗的来说就是我们商家只有100件库存但是卖出去了100+件商品,出现了多买的问题。

出现的场景:举个简单的例子:比如此时只剩下了最后一个商品,有两个人在抢这最后一个商品,此时A进行到了下单的页面,但是网速很慢卡在了这里,此时库存的数量还是没有扣除的一直在转圈圈,但是此时另一个人的网速快已经下单并且支付成功了,此时数据库中的库存数量已经减一变成了0,突然此时A结束转圈了去支付了,也下单了,那么库存就变成了-1,这只是有两个人在同时抢,那么你想想如果有10w人在一起抢呢?这就是典型的超卖问题的出现场景

方案:类似于乐观锁的Redis事务方案

我们知道MySQL数据库中有一个乐观锁机制,乐观锁使用了版本号的原理来进行判断,在进行更新操作之前会去比较此时的版本号和刚开始操作的时候的版本号是不是一致,如果是一致的那么就可以让这个更新操作正常执行。如果此时的版本号不一致了,那么就无法进行更新操作了。拿上面的例子来说,A因为网速慢所以后加载出来购买的页面,那么当A去提交事务的时候去判断版本号发现此时的版本号和一开始的版本号其实是不一致的,就不让这个事务执行,对应的结果就是A无法买到这个商品,所以也就不会超卖了。那么可能会有人说了,我们为什么不直接使用MySQL的这个乐观锁的机制呢?

首先,如果我们要使用这个MySQL的乐观锁机制我们需要对我们之前设计的表进行更改,我们可以需要增加字段用来作为版本号判断,而且可能有很多的表都会涉及到这个机制,所以我们就要修改更多的数据库。你想一下在实际的项目中,你们的代码都写了上万行了,突然因为一个方案去重新设计数据库肯定是不合适的。

如果你们的项目和我这个项目一样使用到了redis来作为缓存的话,那么可以使用我的这个方案,那就是将订单的信息存到redis中,利用redis的事务机制来解决超卖问题。 注意:redis的事务和MySQL的事务可不是一个东东

具体来说就是这样的:

  • 我们将创建的订单的信息放到redis中缓存起来

  • 利用redis的事务机制,下面附上代码,是基于spring boot的项目

    redisTemplate.execute(new SessionCallback() {
        		//重写里面的execute方法
                @Override
                public Object execute(RedisOperations operations) throws DataAccessException {
                    //这里这个key的版本号来进行乐观锁机制
                    operations.watch(你要监听的key,也就是你生成订单放到redis中的key);
                    //标志着开启一个事务
                    operations.multi();
                    //下面只是一个伪代码,举个例子
       				//更新你这个订单被谁买了
                    redisTemplate.opsForValue().set(key,value);
                    //抢单成功之后将这个订单删除,防止被别人买到
                    redisTemplate.delete(key);
                    //类型于MySQL中的提交事务
                    return operations.exec();
                }
            });
    
  • 在上面的代码中,我们将我们要原子操作的命令放到operations.multi();和 return operations.exec();之间,类比于MySQL中就是将一个原子操作放到一个事务中,最后将事务提交,这样redis在做这个操作的时候,watch的这个key就类似于MySQL乐观锁中用来作为版本号的字段,如果有多个任务来进行操作的话会根据这个key来判断是不是应该去执行,只有这个key的版本一致的时候才会去执行成功。否则是执行异常的。

  • 最后还要多说一句,如果你使用了上述的这个方案的话,那么redis的可靠性要得到保证,毕竟你的订单信息存在了redis中,如果宕机了没有好的处理方案的话,那你的订单信息可就都没了,。所以推荐你将redis的持久化策略调成aof模式,如果有条件的话还可以使用主备模式来保证高可用性。

上面的这个方案,简单可行,但是前提是你的项目用到了redis来存你的订单信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

订单业务中的重要问题:超卖问题的解决方案 的相关文章

随机推荐

  • 智能驾驶系统简介和测试要点分析

    智能驾驶系统是一种能够自主感知 决策和执行行驶任务的车辆控制系统 常见的智能驾驶系统包括 自动泊车系统 能够自动控制车辆完成泊车过程 包括寻找车位 转向 加速 制动等操作 自适应巡航系统 能够根据车速 车距和交通状况等因素自适应调整车速 并
  • react实现多选框切换样式逻辑

    import React Component from react class App extends Component constructor props super props this state checkboxItems con
  • time datetime模块 一篇精通

    time datetime python3中time模块的用法 导入 import time 查看time模块内置的能够使用的方法 print dir time 查看内置方法的说明 help time time method help ti
  • NVIDIA驱动安装

    需要去英伟达官网下载适合自己电脑的版本 nvidia网页可以自己测出你的电脑所需要的型号 首先Ctrl Alt F1进入字符界面 删除原有驱动版本 sudo apt get purge nvidia sudo apt get autorem
  • 执行.sh文件(shell脚本)的几种方式

    第一种 要进到shell脚本所在文件夹中 sh helloworld sh 第二种 要进到shell脚本所在文件夹中 bash helloworld sh 第三种 要进到shell脚本所在文件夹中 helloworld sh 第四种 hom
  • uniapp app以及小程序图片添加水印

    const ctx uni createCanvasContext myCanvas const ctx1 uni createCanvasContext myCanvas1 uni getImageInfo src this carInf
  • UiBot如何使用CSS Selector

    UiBot默认的数据抓取可以抓取整个表格 但是有时候我们并不想抓取整个表格 比方说 我们想将下图所有的头像复制到Excel里 这个时候我们无法使用数据抓取功能 因为我们并不是想抓取数据 而是要操作网页里的元素 将上图头像复制到Excel里的
  • Centos7 扩展系统磁盘大小

    Centos7扩展系统磁盘大小 系统盘大小不足 需要扩展系统盘大小 需要添加一块硬盘作为要使用的系统盘的扩展 我的是原来sda就有空间没有分配 所以不用单独再加磁盘了 直接使用sda的未分配的空间 如果是单独新增的一个磁盘例如 dev sd
  • Jenkins 联动 飞书 以签名校验方式 推送测试报告通知消息

    1 获取 飞书 Bot webhook 和 secret 2 python脚本 参考 Song Estelle 的文章 这里重写了部分代码 以签名校验方式发送通知 记得安装相关依赖 usr bin python3 encoding utf
  • Java 中的阻塞队列

    Java 中的阻塞队列 1 ArrayBlockingQueue 由数组结构组成的有界阻塞队列 2 LinkedBlockingQueue 由链表结构组成的有界阻塞队列 3 PriorityBlockingQueue 支持优先级排序的无界阻
  • Python 日期字符串和时间戳解析方法详解

    原文链接 https dreamhomes top posts 202103091919 html 由于从事智能运维AIOps相关的算法研究 因此日常接触的最多就是时间序列相关的数据 在不同场景下时间字符串表示的格式可能都不相同 因此本文记
  • 解决git pull 报错insufficient permission for adding an object to repository database .git/objects

    这个报错是没有 git objects文件的写入权限 可能是 git objects被root角色创建 等到别的角色去操作时就产生了权限问题 所以解决这个问题就要改 git objects的权限 chown R username group
  • Java学习之:异常及其处理方式

    文章目录 1 所有异常都继承 Throwable 类 2 分类 3 为什么要处理异常 4 异常处理格式 5 完整异常信息的取得 5 1 常见的异常 6 throws throw 关键字 6 1 throws 用在定义方法上 6 1 1 用在
  • R中重命名数据框列名小技巧

    R中重命名数据框列名 文章目录 前言 一 基础包names函数和索引 二 使用dplyr rename函数 前言 R语言中两种修改数据框列名的小方法 创建名为df的数据框 一 基础包names函数和索引 将第二列名score修改为popul
  • 深入理解Android之Gradle

    转自 http blog csdn net innost article details 48228651 深入理解Android之Gradle 格式更加精美的PDF版请到 https pan baidu com s 1boG2cLD下载
  • SQL语句中的循环

    SQL语句中的循环 SQL语句中的循环类似于foreach循环 可以循环遍历某个表并进行新增 修改和删除的操作 SQL语句中的循环 使用SQL的游标来实现 上示例 declare ID int 声明变量 名称 类型 begin 开始 pri
  • setFocus不能生效的问题

    focusInEvent只有在对象显示出来的情况下设定setFocus才可以触发 这一点help手册里有说明 转一篇文章如下 http blog csdn net alex201030273437 article details 81937
  • CSV简单了解

    1 CSV介绍 CSV全称是Comma Separate Values 这种文件格式可以作为不同程序之间的数据交互的格式 csv就是一种纯文本文件 如 txt doc等 即是一组字符序列 字符之间已英文字符的逗号或制表符 Tab 分隔 语法
  • Python数据结构-----leetcode232.用栈实现队列

    目录 前言 方法讲解 示例 代码实现 232 用栈实现队列 前言 我们都知道队列的特征是先进先出 就跟排队一样先到先得 而栈的特征是后进后出 那这里我们怎么去通过两个栈来实现一个队列的功能呢 这一期我们一起来学习吧 方法讲解 这里需要准备好
  • 订单业务中的重要问题:超卖问题的解决方案

    订单业务中的重要问题 超卖问题的解决方案 我在做过的一些项目中都涉及到了订单的业务 如果你的项目中有关于订单的业务模块 那肯定说明你的项目中有卖商品的功能 所以有买卖场景就面临一个很常见的一个问题 那就是超卖问题 下面我就整理一下我在做项目