有关电商抢购的具体实现方案实现,首先需要明确我们抢购最关键的因素无非就是商品的库存,具体抢购的那些商品,用户抢购成功后如何和抢购商品形成关联关系。
这个给出大概的思路:
1.进行商品的备货
2.抢购的时候,每抢够成功一次,商品的库存-1,同时记录抢购到该商品的用户。
3.抢购结束后,同步数据,生成相应的订单。
抢购的话,建议采用redis数据库,响应速度快,性能也稳定,也可以承受高并发的访问量,抢购结束后,生成的订单再存放如数据库
在决定解决方案之前,我也曾想过事务这一块的问题,那么如果高并发的情况下,redis怎么处理抢购这一块的事务呢,后面去网上找了一下资料http://www.runoob.com/redis/redis-transactions.html
我的代码操作也是单条语句的,所以具有原子性,因此不用担心事务这一块的问题。
具体的代码实现如下:
第一步,先初始化库存数据,准备开始抢购:
/**
* 初始化产品库存
*/
public void synchronizedProduct() {
redisTemplate.opsForZSet().add("rush", "小米6", 5);
redisTemplate.opsForZSet().add("rush", "小米8", 5);
redisTemplate.opsForZSet().add("rush", "小米9", 5);
redisTemplate.opsForZSet().add("rush", "小米mix3", 5);
}
第二步,开始抢购,获取产品id和关联用户id,如果redis里面的库存已经用完,就显示已售窑,如果抢购成功,根据产品id:sale作为键值key,然后放入一个Map中,其中值是一个List,可以将抢购者的用户id放置List中
控制层代码:
@PostMapping("/shop")
public RestResult rushShop(String productName,Integer userId){
RushResult rushResult = rushService.reduceProduct(productName,userId);
if(rushResult.isSaleOut()){
return new RestResult(200,"抢购成功",rushResult);
}else{
return new RestResult(200,"已售窑",rushResult);
}
}
业务层代码:
/**
* 抢购逻辑
*/
public RushResult reduceProduct(String productName, Integer userId) {
//先获取库存
Double storeValue = redisTemplate.opsForZSet().score("rush", productName);
if (storeValue == null || storeValue == 0) {
//标记字段设置为false
boolean isSaleOut = false;
return new RushResult(storeValue, isSaleOut);
} else {
//库存减一
Double levelStoreValue = redisTemplate.opsForZSet().incrementScore("rush", productName, -1);
//存放进一个List中
redisTemplate.opsForList().rightPush(productName + ":sale", userId);
//抢购成功标记
boolean isSaleOut = true;
return new RushResult(levelStoreValue, isSaleOut);
}
}
第三步,前端刷新页面时,显示最新的数据,将产品库存做一个排序,将最火的排在前面,但其实显示销量的需求不常见,因为很多商家并不愿意透露具体的备货量给客户
public Map rankProduct() {
//获取所有的产品,做一个排序
Set productSet = redisTemplate.opsForZSet().rangeByScore("rush", 0, 1000);
Map rushMap = new LinkedHashMap<>();
for (String productName :
productSet) {
//取出相关的库存
Double storeValue = redisTemplate.opsForZSet().score("rush", productName);
rushMap.put(productName, storeValue);
}
return rushMap;
}
第四步,抢购结束后,将所有的抢购名单内的数据转移到数据库,生成相关订单
public List
redis增加一个配置,确保数据不会被序列化:
/**
* 存储二进制字节码, 所以自定义序列化类
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate
基本代码就如上面展示了
如果关于抢购这一块有更好的实现方式,或者我的文章有不正确的内容,可以在评论区中讨论一下 @_@