java抢购_java redis 实现抢购秒杀

本文介绍了一个基于SpringBoot和Jedis实现的Java抢购秒杀功能。通过Redis的watch和multi事务处理来确保不超卖,但存在并发问题。作者提出将请求放入Kafka或使用RabbitMQ队列来改善并发控制,提供更公平的抢购体验。
摘要由CSDN通过智能技术生成

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 classtest {//@Resource//RedisOperation redisOps;

@ResourceprivateJedisPool jedisPool;@RequestMapping("/redis")public voidredisTest() {

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(newMyRunnable(jedisPool));

}

executor.shutdown();

}public static String getRandomString(int length) { //length是随机字符串长度

String base = "abcdefghijklmnopqrstuvwxyz0123456789";

Random random= newRandom();

StringBuffer sb= newStringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());

sb.append(base.charAt(number));

}returnsb.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 classMyRunnable implements Runnable{privateJedisPool jedisPool;

String userinfo;

String watchkeys= "watchkeys";publicMyRunnable(JedisPool jedisPoo){

jedisPool=jedisPoo;

};public voidrun() {

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 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();

}

}

}

最后是效果

68fc46f727d2a4f894340b795324f409.png

这段代码问题其实还是有的:就是没有按照顺来来抢购

其实我觉得有种方法。就是将请求 存入 kafka中

然后取kafka中前面的数据 一直取到抢购的数量(用户不重复)

这样不就可以了吗,不需要考虑超卖问题啥的。纯属自己的感想。

后来看了一个用rabbitMQ 做的 抢购

把请求插入rabbitMQ队列。然后 消费端订阅数据 来实现抢购。

2018-11-21 今天在github上看到一个秒杀的项目 还不错 分享给大家

这个里面有两个 分支,第二个分支是支持rabbitmq的。我觉得 做的还不完美。不过很有借鉴意义。

java实现秒杀系统@Controller @RequestMapping("seckill")//url:/模块/资源/{id}/细分 /seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) public String list(Model model){ //获取列表页 List list=seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp+model = ModelAndView return "list";//WEB-INF/jsp/"list".jsp } @RequestMapping(value = "/{seckillId}/detail",method = RequestMethod.GET) public String detail(@PathVariable("seckillId") Long seckillId, Model model){ if (seckillId == null){ return "redirect:/seckill/list"; } Seckill seckill = seckillService.getById(seckillId); if (seckill == null){ return "forward:/seckill/list"; } model.addAttribute("seckill",seckill); return "detail"; } //ajax json @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult exposer(@PathVariable("seckillId") Long seckillId){ SeckillResult result; try { Exposer exposer =seckillService.exportSeckillUrl(seckillId); result = new SeckillResult(true,exposer); } catch (Exception e) { logger.error(e.getMessage(),e); result = new SeckillResult(false,e.getMessage()); } return result; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"} ) @ResponseBody public SeckillResult execute(@PathVariable("seckillId")Long seckillId,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值