package com.wanggs.sell.service.impl;
import com.wanggs.sell.enums.ResultEnum;
import com.wanggs.sell.exception.SellException;
import com.wanggs.sell.service.RedisLock;
import com.wanggs.sell.service.SeckillService;
import com.wanggs.sell.util.KeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* @author Wgs
* @version 1.0
* @create:2019/04/02
*/
@Service
public class SeckillServiceImpl implements SeckillService {
@Autowired
private RedisLock redisLock;
private static int TIMEOUT = 10 * 1000;
static Map<String, Integer> products;
static Map<String, Integer> stock;
static Map<String, String> orders;
static {
/**
* 模拟多张表 商品信息表 库存表 秒杀成功订单表
*/
products = new HashMap<>();
stock = new HashMap<>();
orders = new HashMap<>();
products.put("123456", 1000);
stock.put("123456", 1000);
}
private String queryMap(String productId) {
return "双十一秒杀活动,限量份:" + products.get(productId) + "还剩" + stock.get(productId) + " 份" + "" +
"该商品成功下单用户数目:" + orders.size() + " 人";
}
@Override
public String query(String productId) {
return this.queryMap(productId);
}
@Override
public void orderProductMockDiffUser(String productId) {
// 加锁
Long time = System.currentTimeMillis() + TIMEOUT;
if (!redisLock.lock(productId, String.valueOf(time))){
throw new SellException(101,"人太多了,换个姿势抢!!");
}
// 查询商品库存,为0 秒杀结束
int stockNum = stock.get(productId);
if (stockNum == 0) {
throw new SellException(ResultEnum.PRODUCT_STOCK_ERROR);
} else {
// 下单(模拟openId不相同)
orders.put(KeyUtil.genUniqueKey(), productId);
// 减库存
stockNum = stockNum - 1;
try {
//模拟插入数据库
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stock.put(productId, stockNum);
}
System.out.println("-------恭喜抢到-------");
redisLock.unLock(productId, String.valueOf(time));
}
}
package com.wanggs.sell.service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* @author Wgs
* @version 1.0
* @create:2019/04/02
*/
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 加锁
*
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
// 如果说过期
if (StringUtils.isNotBlank(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
// 获取上一个锁
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (StringUtils.isNotBlank(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
}
public void unLock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(currentValue) && value.equals(currentValue)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error("[redis 分布式解锁] 异常:{}", e);
}
}
}
网友评论