服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - 如何通过redis减库存的秒杀场景实现

如何通过redis减库存的秒杀场景实现

2022-10-20 16:03ZNineSun Redis

本文通过解决秒杀系统中的一个场景即数据预加载,即把库存数据事先加载到缓存,然后通过缓存来更新库存,简单介绍了如何通过redis减库存的秒杀场景实现,感兴趣的可以了解一下

Redis扣库存,主要目的是减少对数据库的访问,之前的减库存,直接访问数据库,读取库存,当高并发请求到来的时候,大量的读取数据有可能会导致数据库的崩溃。

大家可以先读一下《秒杀系统设计》对整体的秒杀流程有个了解之后,在来读一下这篇文章。

本文只是解决秒杀系统中的一个场景即数据预加载,即把库存数据事先加载到缓存,然后通过缓存来更新库存。

使用思路:

  • 系统初始化的时候,将商品库存加载到Redis 缓存中保存。
  • 收到请求的时候,先在Redis中拿到该商品的库存值,进行库存预减,如果减完之后库存不足,直接返回逻辑Exception就不需要访问数据库再去减库存了,如果库存值正确,进行下一步。
  • 将请求入队,立即给前端返回一个值,表示正在排队中,然后进行秒杀逻辑,后端队列进行秒杀逻辑,前端轮询后端发来的请求,如果秒杀成功,返回秒杀,成功,不成功就返回失败。

第一步:系统初始化后就将所有商品库存放入缓存

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * 秒杀接口优化之---   第一步:  系统初始化后就将所有商品库存放入 缓存
 */
@Override
public void afterPropertiesSet() throws Exception {
    List<GoodsVo> goods = goodsService.getGoodsList();
    if (goods == null) {
        return;
    }
    for (GoodsVo goodsVo : goods) {
        redisService.set(GoodsKey.getId(), goodsVo.getStockCount());
        isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有
    }
}

第二步: 预减库存从缓存中减库存

?
1
2
3
4
5
6
7
8
9
/**秒杀接口优化之 ----第二步: 预减库存 从缓存中减库存
 * 利用 redis 中的方法,减去库存,返回值为 减去1 之后的值
 * */
long stock = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId);
/*这里判断不能小于等于,因为减去之后等于 说明还有是正常范围*/
if (stock < 0) {
    isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true
    return Result.error(CodeMsg.MIAO_SHA_NO_STOCK);
}

整体的逻辑如下:

1.先将所有数据读出来,初始化到缓存中,并以 stock + goodid 的形成存入Redis。

2.在秒杀的时候,先进行预减库存检测,从redis中,利用decr 减去对应商品的库存,如果库存小于0,说明此时 库存不足,则不需要访问数据库。直接抛出异常即可。
我们上面还使用到了isOverMap,这个是内存标记。

内存标记

由于接口优化很多基于Redis的缓存操作,当并发很高的时候,也会给Redis服务器带来很大的负担,如果可以减少对Redis服务器的访问,也可以达到的优化的效果。

于是,可以加一个内存map,标记对应商品的库存量是否还有,在访问Redis之前,在map中拿到对应商品的库存量标记,就可以不需要访问Redis 就可以判断没有库存了。

1.生成一个map,并在初始化的时候,将所有商品的id为键,标记false 存入map中。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Map<Long, Boolean> isOverMap = new HashMap<Long, Boolean>();
/**
 * 秒杀接口优化之---   第一步:  系统初始化后就将所有商品库存放入 缓存
 */
@Override
public void afterPropertiesSet() throws Exception {
    List<GoodsVo> goods = goodsService.getGoodsList();
    if (goods == null) {
        return;
    }
    for (GoodsVo goodsVo : goods) {
        redisService.set(GoodsKey.getGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount());
        isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有
    }
}
?
1
2
3
4
5
6
7
8
9
10
/**再优化: 优化 库存之后的请求不访问redis 通过判断 对应 map 的值
  * */
boolean isOver = isOverMap.get(goodsId);
if (isOver) {
     return Result.error(CodeMsg.MIAO_SHA_NO_STOCK);
}
 
if (stock < 0) {
     isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true
}

2.在预减库存之前,从map中取标记,若标记为false,说明库存

3.预减库存,当遇到库存不足的时候,将该商品的标记置为true,表示该商品的库存不足。这样,下面的所有请求,将被拦截,无需访问redis进行预减库存。

所以利用缓存的整体思路如下:

将商品的库存数据加载至内存,同时初始化内存标记,即把每个产品的id存放至map,都是初始化为false,在每次需要执行秒杀逻辑之前,在在内存标记中取值,如果仍有库存即map里返回的为false,则 执行秒杀逻辑,否则直接抛出异常。

同时扣减库存时,需要判断缓存中的库存数量是否仍然大于0,如果小于等于0,修改内存标记。

到此这篇关于如何通过redis减库存的秒杀场景实现的文章就介绍到这了,更多相关redis减库存内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/zhiyikeji/article/details/125050768

延伸 · 阅读

精彩推荐
  • RedisRedisson如何解决Redis分布式锁提前释放问题

    Redisson如何解决Redis分布式锁提前释放问题

    本文主要介绍了Redisson如何解决Redis分布式锁提前释放问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋...

    柏油11562022-10-19
  • Redis详解redis脚本命令执行问题(redis.call)

    详解redis脚本命令执行问题(redis.call)

    这篇文章主要介绍了redis脚本命令执行问题(redis.call),分别介绍了redis-cli命令行中执行及linux命令行中执行问题,本文给大家介绍的非常详细,需要的朋友参...

    hjseo_seg3322022-10-11
  • RedisRedis数据库的使用场景介绍(避免误用Redis)

    Redis数据库的使用场景介绍(避免误用Redis)

    这篇文章主要介绍了Redis数据库的使用场景介绍(避免误用Redis),本文用简要的语言总结了Redis数据库的适应场合,人而避免错误的使用它而产生昂贵的维护...

    Redis教程网4982019-10-22
  • RedisCentos7.3安装Redis4.0.6详细图文教程

    Centos7.3安装Redis4.0.6详细图文教程

    这篇文章主要介绍了Centos7.3安装Redis4.0.6详细教程图解,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 ...

    刀尘2892019-11-18
  • Redis为什么断电后Redis数据不会丢失

    为什么断电后Redis数据不会丢失

    Redis 作为一款内存数据库,被广泛使用于缓存,分布式锁等场景,那么假如断电或者因其他因素导致 Reids 服务宕机,在重启之后数据会丢失吗?本文就来介...

    双子孤狼5652021-09-16
  • RedisRedis五种数据结构在JAVA中如何封装使用

    Redis五种数据结构在JAVA中如何封装使用

    本篇博文就针对Redis的五种数据结构以及如何在JAVA中封装使用做一个简单的介绍。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    肝铁侠8202021-11-30
  • Redisredis客户端连接错误 NOAUTH Authentication required

    redis客户端连接错误 NOAUTH Authentication required

    本文主要介绍了redis客户端连接错误 NOAUTH Authentication required,详细的介绍了解决方法,感兴趣的可以了解一下...

    轻尘×9152021-08-16
  • RedisRedis 实现“附近的人”功能

    Redis 实现“附近的人”功能

    Redis基于geohash和有序集合提供了地理位置相关功能。这篇文章主要介绍了Redis 实现“附近的人”功能,需要的朋友可以参考下 ...

    Winner1923092019-11-28