首页 > 数据库 >Redis实战(黑马点评--优惠券秒杀)

Redis实战(黑马点评--优惠券秒杀)

时间:2024-07-09 17:55:29浏览次数:16  
标签:优惠券 扣减 -- Redis 库存 voucher id stock

一、redis实现全局唯一订单id

1、问题:使用数据库自增id不合适

当用户抢购商品时,生成的订单会保存到tb_voucher_order表中,而订单表如果使用数据库自增ID就会存在一些问题

  1. id规律性太明显
  2. 受单表数据量的限制

2、解决方法:全局id生成器

  • 符号位:1bit,永远为0
  • 时间戳:31bit,以秒为单位,可以使用69年(2^31秒约等于69年)
  • 序列号:32bit,秒内的计数器,支持每秒传输2^32个不同ID
 
@Component
public class RedisIdWorker {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //设置起始时间,我这里设定的是2022.01.01 00:00:00
    public static final Long BEGIN_TIMESTAMP = 1640995200L;
    //序列号长度
    public static final Long COUNT_BIT = 32L;

    public long nextId(String keyPrefix){
        //1. 生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long currentSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timeStamp = currentSecond - BEGIN_TIMESTAMP;
        //2. 生成序列号
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        long count = stringRedisTemplate.opsForValue().increment("inc:"+keyPrefix+":"+date);
        //3. 拼接并返回,简单位运算
        return timeStamp << COUNT_BIT | count;
    }

    public static void main(String[] args) {
        //设置一下起始时间,时间戳就是起始时间与当前时间的秒数差
        LocalDateTime tmp = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        System.out.println(tmp.toEpochSecond(ZoneOffset.UTC));
        //结果为1640995200L
    }
}

二、实现秒杀下单

脑图:

 

1、出现的问题(最后一张票时):多线程并行查询库存后,再减库存,会导致超卖。

2、解决方法:乐观锁,执行更新库存时,先比较:查询到的优惠券库存和实际数据库中优惠券库存是否相同

// 5.扣减库存
        boolean success = seckillVoucherService.update().setSql("stock = stock - 1")   // set stock = stock - 1
                .eq("voucher_id", voucherId).eq("stock", voucher.getStock())   // where id = ? and stock = ?
                .update();
        if (!success) {
            return Result.fail("库存不足");
        }
  • 以上逻辑的核心含义是:只要我扣减库存时的库存和之前我查询到的库存是一样的,就意味着没有人在中间修改过库存,那么此时就是安全的,但是以上这种方式通过测试发现会有很多失败的情况,失败的原因在于:在使用乐观锁过程中假设100个线程同时都拿到了100的库存,然后大家一起去进行扣减,但是100个人中只有1个人能扣减成功,其他的人在处理时,他们在扣减时,库存已经被修改过了,所以此时其他线程都会失败
  • 那么我们继续完善代码,修改我们的逻辑,在这种场景,我们可以只判断是否有剩余优惠券,即只要数据库中的库存大于0,都能顺利完成扣减库存操作
// 5.扣减库存
        boolean success = seckillVoucherService.update().setSql("stock = stock - 1")   // set stock = stock - 1
                .eq("voucher_id", voucherId) //.eq("stock", voucher.getStock())   // where id = ? and stock = ?
                .gt("stock", 0)
                .update();
        if (!success) {
            return Result.fail("库存不足");
        }

 

标签:优惠券,扣减,--,Redis,库存,voucher,id,stock
From: https://www.cnblogs.com/fengok/p/17872938.html

相关文章

  • 探秘odpdx32.dll:核心功能解析与缺失修复指南
    odpdx32.dll是一个动态链接库(DLL)文件,通常与DirectX或OpenGL相关的软件或游戏有关。这个文件可能包含了用于处理图形渲染和多媒体播放的函数和资源,是系统中重要的组件之一。当你的计算机在运行某些应用程序时提示缺少odpdx32.dll文件,这意味着该应用程序依赖于这个文件,但当前系......
  • 各种软件启动方式
    各种软件启动方式1.MySQL#启动servicemysqldstart#关闭servicemysqldstop#重启servicemysqldrestart2.Redis#启动serviceredisdstart#关闭serviceredisdstop3.nginx#启动./nginx#关闭./nginx-squit#快速关闭./nginx-sstop#重新加载......
  • 深入解析:api-ms-win-net-isolation-l1-1-0.dll的角色与丢失修复指南
    api-ms-win-net-isolation-l1-1-0.dll是一个Windows操作系统中的动态链接库(DLL)文件,它与网络隔离功能相关,属于WindowsAppContainer和WindowsSandbox功能的一部分。这个DLL文件负责处理网络请求的隔离,确保应用程序在AppContainer或Sandbox环境中只能访问授权的网络资源,这对于增......
  • 国开大学2024《社会保障基础(统设课)》
    1.养老保险通过强制性的分摊机制,为老年人提供足够收入以维持退休后的基本生活水平,防范老年风险,这是养老保险的()。答案:B.保险功能2.职工达到法定退休年龄,缴费未满15年,则()。答案:D.一次性领取个人账户储存额3.目前我国养老保险基金筹集的主要模......
  • 做题小结-含做不来的计数DP
    第一个题首先这个题我没做出来我在这里还是要总结下基环树喜欢考什么我以前做过一个交互题题目大意忘了反正考的是基环树最重要的一个性质两个点之间一定存在两个走法,一个是正常走另一个是走环反正就是一定有两条路过来那这个题就是考虑这个性质还有就是正常树的要找......
  • swagger注解文档
    swagger注解文档1.@Api()作用于类,放置于controller的一个类上,标志这个类是swagger资源1.1参数:参数名称参数介绍备注value说明,可以使用tags替代tags说明1.2实例代码:@Api(value="swagger2测试api",tags="管理员")@RequestMapping("/api/a......
  • 【狂神说Java】系列学习笔记01——MarkDown语法
    #MarkDown学习本文为B站老师秦疆【狂神说Java】系列,课堂学习笔记,主要联练习的是MarkDown的使用方法,老师的博客链接我没找到,广告1.标题+加粗2级3级4级5级6级最多七级标题Helloworld!Helloworld!Helloworld!Helloworld!引用-沐风6标题一级标题(#+空格)二......
  • git提交emoji指南
    emoji指南emojiemoji代码commit说明......
  • 题解 - 幻象迷宫
    题目in洛谷或题目inCF题目幻象迷宫可以认为是无限大的,不过它由若干个\(N\timesM\)的矩阵重复组成。矩阵中有的地方是道路,用\(\verb!.!\)表示;有的地方是墙,用\(\verb!#!\)表示。起始位置用\(\verb!S!\)表示。也就是对于迷宫中的一个点\((x,y)\),如果\((x\bmodn,y......
  • C++关于计算浮点数小数位数时遇到的浮点数精确度问题(以及浮点数强制转换问题)
    起因是当我想要计算浮点数的小数位位数(利用当浮点数num减去其整数位)我的想法是先分离出小数位,然后每次循环给小数位乘上10,直到不存在小数位时,就会满足当num-(int)num==0通过这种方式就可以得到小数位的长度#include<iostream>usingnamespacestd;intmain(){doubl......