您的位置:首页 > 数据库 > Redis

spring boot + Mybatis + redis 秒杀系统

2017-09-19 09:18 501 查看
最近开了一些高并发的东西,以及一些秒杀系统,但感觉都没有完整的描述。于是自己就动手实现了一个简单版本的抢购系统。

本系统采用spring boot + mybatis + redis实现。

项目结构图如下:



项目工程已放到GitHub上了,https://github.com/feibabm/seckill,需要的请自行下载。

本文主要借鉴网上一些通用的做法,做出一个例子,主要实现了一个抢购接口:
http://localhost:8080/seckill/product/1?userId=1
seckill.sql文件为建表sql

pro_insert.sql文件为success_killed表中数据添加10000条用户预约记录

seckill_insert.sql文件为seckill生成一条产品信息

具体验证逻辑是执行test文件夹下的两个test类:

RemoteInvote.java

RemoteInvote2.java

这两个test类没有什么差别,主要是为了增加并发量

主要的抢票逻辑如下:



public SecKillResult secKillProduct(String userPhone, long productId) {
String state = (String)redisTemplate.opsForValue().get(userPhone + "_"+ productId);
//用户信息加载
if(null == state){
SuccessKilled successKilled = new SuccessKilled();
successKilled.setSeckillId(productId);
successKilled.setUserPhone(Long.valueOf(userPhone));
successKilled = successKilledMapper.selectOne(successKilled);
if(null == successKilled){
return new SecKillResult(false, "该用户没有预约");
}else{
synchronized (this){
state = (String)redisTemplate.opsForValue().get(userPhone + "_"+ productId);
if(null == state){
redisTemplate.opsForValue().set(userPhone + "_" + productId, successKilled.getState().toString(), 300, TimeUnit.SECONDS);
state = String.valueOf(successKilled.getState());
}
}

}
}
if(state.equals("-1")){
//查询产品信息
//            ProductInfo productInfo = (ProductInfo)redisTemplate.opsForValue().get(productId + "");
List values = redisTemplate.opsForHash().values(productId + "");
if(values.size() == 0){
Seckill seckill = seckillMapper.selectByPrimaryKey(productId);
if(null == seckill){
return new SecKillResult(false, "没有该秒杀商品信息");
}
synchronized (this){
if(!redisTemplate.opsForHash().hasKey(productId + "", "number")){
//                        productInfo = new ProductInfo(seckill.getSeckillId(), seckill.getNumber(), seckill.getStartTime(), seckill.getEndTime());
HashMap<String, String> productHash = new HashMap<>();
productHash.put("number", seckill.getNumber() + "");
productHash.put("startTime", seckill.getStartTime().getTime() + "");
productHash.put("endTime", seckill.getEndTime().getTime() + "");
redisTemplate.opsForHash().putAll(productId +"", productHash);
redisTemplate.expire(productId + "", 300, TimeUnit.SECONDS);
values = redisTemplate.opsForHash().values(productId + "");
}
}
}
if( new Date(Long.valueOf((String)values.get(1))).after(new Date(System.currentTimeMillis()))){
return new SecKillResult(false, "抢购还没有开始");
} else if(new Date(Long.valueOf((String)values.get(2))).before(new Date(System.currentTimeMillis()))){
return new SecKillResult(false, "抢购已经结束");
} else {
Long userState = redisTemplate.opsForValue().increment(userPhone + "_" + productId, 1);
if(userState == 0){
//                    Long increment = redisTemplate.opsForValue().increment(productId, -1);
Long number = redisTemplate.opsForHash().increment(productId + "", "number", -1);
if(number >= 0){
//消息队列异步更新库存,以及用户的预约信息
QueueEntity queueEntity = new QueueEntity(userPhone, productId);
ExecutorPool.queue.offer(queueEntity);
}else {
return new SecKillResult(false, "商品已经抢购完成");
}
}else {
redisTemplate.opsForValue().increment(userPhone + "_" + productId, -1);
return new SecKillResult(false, "您已抢购过该产品");
}
}
} else {
return new SecKillResult(false, "您已抢购过该产品");
}
return null;
}


自己用两进程线程,大概两分钟掉了20000次,暂时没有出现啥问题。如果有什么问题,希望大家指出,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring redis mybatis
相关文章推荐