Redis+Lua实现简易的秒杀抢购

1 商品抢购

主要逻辑是:减库存,记录抢购成功的用户

@RestController
public class DemoController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String GOODS_STOCK_KEY = "goods:001";  //  秒杀商品库存
    private static final String GOODS_USER_KEY = "users:001";   //  抢购成功的用户列表

    /**
     * 在不加锁的情况下,会发生超卖
     */
    @GetMapping("/seckill")
    public String seckill() {
        int userId = (int) (Math.random() * 1000);

        ValueOperations valueOps = stringRedisTemplate.opsForValue();
        ListOperations listOps = stringRedisTemplate.opsForList();

        int stock = Integer.parseInt(valueOps.get(GOODS_STOCK_KEY));

        if (stock > 0) {
            valueOps.decrement(GOODS_STOCK_KEY);
            listOps.leftPush(GOODS_USER_KEY, String.valueOf(userId));
            return "抢购成功";
        } else {
            return "商品已售罄";
        }
    }

    /**
     * 将多个命令打包成一个原子操作,利用redis单线程执行命令的特性,在不加锁的情况下避免了资源竞争
     */
    @GetMapping("/seckill_lua")
    public String seckill_lua() {
        int userId = (int) (Math.random() * 1000);

        String script = "if tonumber(redis.call('get', KEYS[1])) > 0 then " +
                "redis.call('decr', KEYS[1]); " +
                "redis.call('lpush', KEYS[2], ARGV[1]); " +
                "return 1; " +
                "else " +
                "return 0; " +
                "end; ";

        DefaultRedisScript redisScript = new DefaultRedisScript();
        redisScript.setResultType(Long.class);
        redisScript.setScriptText(script);

        List keyList = Arrays.asList(GOODS_STOCK_KEY, GOODS_USER_KEY);

        Long result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(userId));

        if (result == 1) {
            return "抢购成功";
        } else {
            return "商品已售罄";
        }
    }
}

对比两次的结果:

Redis+Lua实现简易的秒杀抢购

2 多线程处理Excel导入

/**
 * 多线程处理Excel导入
 *
 * PS:
 *  Executors返回的线程池对象的弊端如下:
 *  (1) FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
 *  (2) CachedThreadPool: 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
 */
@PostMapping
public void excelImport() throws InterruptedException {
    //  待处理的数据(比如:从Excel中读取的数据)
    List dataList = new ArrayList();

    //  多线程处理
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    CountDownLatch countDownLatch = new CountDownLatch(dataList.size());
    for (Object obj : dataList) {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {

                } catch (Exception ex) {

                } finally {
                   countDownLatch.countDown();
                }
            }
        });
    }

    countDownLatch.await(30, TimeUnit.SECONDS);

    //  后续执行

    //  返回结果
}

Original: https://www.cnblogs.com/cjsblog/p/16438567.html
Author: 废物大师兄
Title: Redis+Lua实现简易的秒杀抢购

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612190/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Spark学习(4) Spark Streaming

    Apache Flink SparkSteaming Storm 架构介于spark和storm之间,主从结构与sparkStreaming相似,DataFlow Grpah与st…

    数据库 2023年6月16日
    0114
  • MySQL8.0 redo日志系统优化

    现在主流的数据库系统的故障恢复逻辑都是基于经典的ARIES协议,也就是基于undo日志+redo日志的来进行故障恢复。redo日志是物理日志,一般采用WAL(Write-Ahead…

    数据库 2023年6月9日
    0134
  • 2018年最新JAVA面试题总结之框架(4)

    转自于:https://zhuanlan.zhihu.com/p/40098726 1、谈谈对spring框架的了解 ,spring有什么作用(IOC,AOP),spring的核心…

    数据库 2023年6月16日
    0126
  • Dubbo源码(一)-SPI使用

    Dubbo 的可扩展性是基于 SPI 去实现的,而且Dubbo所有的组件都是通过 SPI 机制加载。 SPI 全称为 (Service Provider Interface) ,是…

    数据库 2023年6月11日
    0133
  • PLSQL_developer安装与配置

    前言: 记录安装与配置操作 环境: 客户机:windows服务器:虚拟机中的windows server 2003/————&#82…

    数据库 2023年6月11日
    0121
  • Redis集群(二)哨兵模式

    一、作用和架构 1. 作用 Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是 主节点的自动故障转移。下面是Redis官方文档对于哨…

    数据库 2023年6月11日
    0125
  • Java面试题(二)–MySQL

    1 存储引擎 1、简单描述一个Mysql的内部结构? MySQL的基本架构示意图:大体来说,MySQL可以分为 server层和 存储引擎层两部分。 ① server层包括连接器、…

    数据库 2023年5月24日
    0169
  • 对实体 “xxxxxx” 的引用必须以 ‘;’ 分隔符结尾。

    在配置才c3p0-config.xml文件时,向在Mysql连接的url中加入属性,结果报错 原因是因为 & 符号在XML格式的文件中需要进行转义 只需要把 & 换…

    数据库 2023年6月6日
    0123
  • Java 中的线程池

    为什么要用线程池 在 HotSpot VM 的线程模型中,Java 线程被一对一映射为内核线程。 Java 在使用线程执行程序时,需要调用操作系统内核的 API,创建一个内核线程,…

    数据库 2023年6月11日
    0117
  • zabbix监控配置流程

    1.0 zabbix监控配置流程详细 管理角度: 开发 由开发人员提供监控指标来监控 运营 让其找开发要监控指标 运维 直接加 配置角度: 创建主机 创建主机组并加入主机 添加监控…

    数据库 2023年6月14日
    0136
  • 一个反直觉的sql

    引子 在《容易引起雪崩的两个处理》里,我提到一个慢查询的问题。本文先从整洁架构的角度讲讲慢查询sql完成的功能以及设计,再介绍对sql进行的实施测试现象以及思考。 设计讲解 眼看着…

    数据库 2023年5月24日
    0138
  • MySQL学习(3)—MySQL常用命令

    ps:此随笔基于mysql 5.7.*版本。 准备 net start mysql 启动MySQL服务 net stop mysql 关闭MySQL服务 mysql [-h exi…

    数据库 2023年6月14日
    0118
  • dockerfile

    基本结构 Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。 Dockerfile 由一行行命令语句组成,并且支持以 # 开头…

    数据库 2023年6月14日
    0128
  • Java学习-第一部分-第二阶段-项目实战:坦克大战【3】

    坦克大战【3】 笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 坦克大战0.6版 √增加功能 2. 记录玩家的成…

    数据库 2023年6月11日
    0155
  • mybatis批量操作

    List类型 Mapper.java public int updateAccount(List<orderjob> orderJobs);</orderjob&…

    数据库 2023年6月16日
    0126
  • 自定义表单 动态表单 表单设计器 流程引擎 设计方案

    作流模块——————————- 1.模型管理 :web在线流…

    数据库 2023年6月6日
    0116
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球