ToB企服应用市场:ToB评测及商务社交产业平台

标题: Redis+Lua实现简易的秒杀抢购 [打印本页]

作者: 花瓣小跑    时间: 2022-8-21 20:02
标题: Redis+Lua实现简易的秒杀抢购
1  商品抢购
主要逻辑是:减库存,记录抢购成功的用户
  1. @RestController
  2. public class DemoController {
  3.     @Resource
  4.     private StringRedisTemplate stringRedisTemplate;
  5.     private static final String GOODS_STOCK_KEY = "goods:001";  //  秒杀商品库存
  6.     private static final String GOODS_USER_KEY = "users:001";   //  抢购成功的用户列表
  7.     /**
  8.      * 在不加锁的情况下,会发生超卖
  9.      */
  10.     @GetMapping("/seckill")
  11.     public String seckill() {
  12.         int userId = (int) (Math.random() * 1000);
  13.         ValueOperations<string, string=""> valueOps = stringRedisTemplate.opsForValue();
  14.         ListOperations<string, string=""> listOps = stringRedisTemplate.opsForList();
  15.         int stock = Integer.parseInt(valueOps.get(GOODS_STOCK_KEY));
  16.         if (stock > 0) {
  17.             valueOps.decrement(GOODS_STOCK_KEY);
  18.             listOps.leftPush(GOODS_USER_KEY, String.valueOf(userId));
  19.             return "抢购成功";
  20.         } else {
  21.             return "商品已售罄";
  22.         }
  23.     }
  24.     /**
  25.      * 将多个命令打包成一个原子操作,利用redis单线程执行命令的特性,在不加锁的情况下避免了资源竞争
  26.      */
  27.     @GetMapping("/seckill_lua")
  28.     public String seckill_lua() {
  29.         int userId = (int) (Math.random() * 1000);
  30.         String script = "if tonumber(redis.call('get', KEYS[1])) > 0 then " +
  31.                 "redis.call('decr', KEYS[1]); " +
  32.                 "redis.call('lpush', KEYS[2], ARGV[1]); " +
  33.                 "return 1; " +
  34.                 "else " +
  35.                 "return 0; " +
  36.                 "end; ";
  37.         DefaultRedisScript<long> redisScript = new DefaultRedisScript();
  38.         redisScript.setResultType(Long.class);
  39.         redisScript.setScriptText(script);
  40.         List<string> keyList = Arrays.asList(GOODS_STOCK_KEY, GOODS_USER_KEY);
  41.         Long result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(userId));
  42.         if (result == 1) {
  43.             return "抢购成功";
  44.         } else {
  45.             return "商品已售罄";
  46.         }
  47.     }
  48. }</string></long></string,></string,>
复制代码
2  多线程处理Excel导入
  1. /**
  2. * 多线程处理Excel导入
  3. *
  4. * PS:
  5. *  Executors返回的线程池对象的弊端如下:
  6. *  (1) FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
  7. *  (2) CachedThreadPool: 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
  8. */
  9. @PostMapping
  10. public void excelImport() throws InterruptedException {
  11.     //  待处理的数据(比如:从Excel中读取的数据)
  12.     List dataList = new ArrayList();
  13.     //  多线程处理
  14.     ExecutorService executorService = Executors.newFixedThreadPool(5);
  15.     CountDownLatch countDownLatch = new CountDownLatch(dataList.size());
  16.     for (Object obj : dataList) {
  17.         executorService.submit(new Runnable() {
  18.             @Override
  19.             public void run() {
  20.                 try {
  21.                 } catch (Exception ex) {
  22.                 } finally {
  23.                    countDownLatch.countDown();
  24.                 }
  25.             }
  26.         });
  27.     }
  28.     countDownLatch.await(30, TimeUnit.SECONDS);
  29.     //  后续执行
  30.     //  返回结果
  31. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4