java redis 实现抢购秒杀
Posted 2019美丽的梦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java redis 实现抢购秒杀相关的知识,希望对你有一定的参考价值。
2018.10.24 今天研究了下抢购秒杀的功能实现
网上查了一大堆 用redis的最多。
主要是通过redis的 watch multi 事务来控制秒杀数量 不超卖。
这里说下自己的感受:
不超卖的话 那就要一个个的来减库存 这样的话 效率上会有点问题 这里上下代码 基本上是再网上抄的 。
我用的是 springboot jedis
我就直接上代码了
Controller层
package com.bicon.basedemo.controller; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.annotation.Resource; import org.omg.CORBA.PRIVATE_MEMBER; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; @RestController @RequestMapping("/test") public class test { // @Resource // RedisOperation redisOps; @Resource private JedisPool jedisPool; @RequestMapping("/redis") public void redisTest() { Jedis jedis = jedisPool.getResource(); final String watchkeys = "watchkeys"; ExecutorService executor = Executors.newFixedThreadPool(20); //20个线程池并发数 jedis.set(watchkeys, "10");//设置起始的抢购数 // jedis.del("setsucc", "setfail"); jedis.close(); for (int i = 0; i < 101; i++) {//设置101个人来发起抢购 模拟101个人抢购 executor.execute(new MyRunnable(jedisPool)); } executor.shutdown(); } public static String getRandomString(int length) { //length是随机字符串长度 String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
MyRunnable 代码
package com.bicon.basedemo.controller; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Transaction; public class MyRunnable implements Runnable{ private JedisPool jedisPool; String userinfo; String watchkeys = "watchkeys"; public MyRunnable(JedisPool jedisPoo){ jedisPool = jedisPoo; }; public void run() { Jedis jedis = jedisPool.getResource(); try { jedis.watch(watchkeys);// watchkeys String val = jedis.get(watchkeys); int valint = Integer.valueOf(val); if (valint <= 100 && valint>=1) { Transaction tx = jedis.multi();// 开启事务 // tx.incr("watchkeys"); tx.incrBy("watchkeys", -1); List<Object> list = tx.exec();// 提交事务,如果此时watchkeys被改动了,则返回null if (list == null ||list.size()==0) { System.out.println("重新抢购"); this.run(); return; } else { for(Object succ : list){ String succuserifo ="succ"+succ.toString() +userinfo ; String succinfo="用户:" + succuserifo + "抢购成功,当前抢购成功人数:" + (1-(valint-10)); System.out.println(succinfo); /* 抢购成功业务逻辑 */ jedis.setnx(succuserifo, succinfo); } } } else { String failuserifo ="kcfail" + userinfo; String failinfo1="用户:" + failuserifo + "商品被抢购完毕,抢购失败"; System.out.println(failinfo1); jedis.setnx(failuserifo, failinfo1); return; } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } } }
最后是效果
这段代码问题其实还是有的:就是没有按照顺来来抢购
其实我觉得有种方法。就是将请求 存入 kafka中
然后取kafka中前面的数据 一直取到抢购的数量(用户不重复)
这样不就可以了吗,不需要考虑超卖问题啥的。纯属自己的感想。
后来看了一个用rabbitMQ 做的 抢购
把请求插入rabbitMQ队列。然后 消费端订阅数据 来实现抢购。
2018-11-21 今天在github上看到一个秒杀的项目 还不错 分享给大家
https://github.com/hfbin/Seckill
这个里面有两个 分支,第二个分支是支持rabbitmq的。我觉得 做的还不完美。不过很有借鉴意义。
以上是关于java redis 实现抢购秒杀的主要内容,如果未能解决你的问题,请参考以下文章