谷粒商城秒杀商品上架(四十六)
310-320秒杀商品上架
断断续续差不多敲了3个月,这个星期差不多可以把高级结束,集群还有30级,下周应该可以把谷粒商城全部完结。
代码已经上传:https://gitee.com/dalianpai/gulimall
/**
* @author WGR
* @create 2020/8/17 -- 22:08
*/
@Slf4j
@Service
public class SeckillSkuScheduled {
@Autowired
SeckillService seckillService;
@Autowired
RedissonClient redissonClient;
private final String upload_lock = "seckill:upload:lock";
@Scheduled(cron ="0 * 3 * * ?")
public void uploadSeckillSkulatest3Days(){
log.info("商品上架");
RLock lock = redissonClient.getLock(upload_lock);
lock.lock(10, TimeUnit.SECONDS);
try{
seckillService.uploadSeckillSkuLatest3Days();
}finally {
lock.unlock();
}
}
}
主要的service方法
/**
* @author WGR
* @create 2020/8/17 -- 22:09
*/
@Service
public class SeckillServiceImpl implements SeckillService {
@Autowired
CouponFeignService couponFeignService;
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
ProductFeignService productFeignService;
@Autowired
RedissonClient redissonClient;
private final String SESSIONS_CACHE_PREFIX ="seckill:sessions:";
private final String SKUKILL_CACHE_PREDIX ="seckill:skus";
private final String SKU_STOCK_SEMPHORE ="seckill:stock:";
@Override
public void uploadSeckillSkuLatest3Days() {
R session = couponFeignService.lates3DaySession();
if(session.getCode()==0){
List<SeckillSessionsWithSkus> sessionData = session.getData(new TypeReference<List<SeckillSessionsWithSkus>>(){});
System.out.println(sessionData);
saveSessionInfos(sessionData);
saveSessionSkuInfos(sessionData);
}
}
@Override
public List<SecKillSkuRedisTo> getCurrentSeckillSkus() {
// 1.确定当前时间属于那个秒杀场次
long time = new Date().getTime();
Set<String> keys = redisTemplate.keys(SESSIONS_CACHE_PREFIX + "*");
for (String key : keys) {
String replace = key.replace("seckill:sessions:", "");
String[] split = replace.split("_");
long start = Long.parseLong(split[0]);
long end = Long.parseLong(split[1]);
if(time >= start && time <= end){
// 2.获取这个秒杀场次的所有商品信息
List<String> range = redisTemplate.opsForList().range(key, 0, 100);
BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREDIX);
List<String> list = hashOps.multiGet(range);
if(list != null){
return list.stream().map(item -> {
SecKillSkuRedisTo redisTo = JSON.parseObject(item, SecKillSkuRedisTo.class);
return redisTo;
}).collect(Collectors.toList());
}
break;
}
}
return null;
}
@Override
public SecKillSkuRedisTo getSkuSeckillInfo(Long skuId) {
BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREDIX);
Set<String> keys = hashOps.keys();
if(keys != null && keys.size() > 0){
String regx = "\\d+_" + skuId;
for (String key : keys) {
if(Pattern.matches(regx, key)){
String json = hashOps.get(key);
SecKillSkuRedisTo to = JSON.parseObject(json, SecKillSkuRedisTo.class);
// 处理一下随机码
long current = new Date().getTime();
if(current <= to.getStartTime() || current >= to.getEndTime()){
to.setRandomCode(null);
}
System.out.println(to);
return to;
}
}
}
return null;
}
private void saveSessionInfos(List<SeckillSessionsWithSkus> sessions){
sessions.stream().forEach(session ->{
long startTime = session.getStartTime().getTime();
long endTime = session.getEndTime().getTime();
String key = SESSIONS_CACHE_PREFIX + startTime + "_" + endTime;
Boolean hasKey = redisTemplate.hasKey(key);
if(!hasKey){
List<String> collect = session.getRelationSkus().stream().map(item -> item.getPromotionSessionId().toString()+"_"+item.getSkuId().toString()).collect(Collectors.toList());
//缓存活动信息
redisTemplate.opsForList().leftPushAll(key,collect);
}
});
}
private void saveSessionSkuInfos(List<SeckillSessionsWithSkus> sessions){
sessions.stream().forEach(session ->{
BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(SKUKILL_CACHE_PREDIX);
session.getRelationSkus().stream().forEach(seckillSkuVo -> {
String token = UUID.randomUUID().toString().replace("-", "");
if(!ops.hasKey(seckillSkuVo.getPromotionSessionId().toString()+"_"+seckillSkuVo.getSkuId().toString())){
SecKillSkuRedisTo redisTo = new SecKillSkuRedisTo();
R skuInfo = productFeignService.info(seckillSkuVo.getSkuId());
if(skuInfo.getCode() ==0){
SkuInfoVo info = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
});
redisTo.setSkuInfo(info);
}
//2.sku的秒杀信息
BeanUtils.copyProperties(seckillSkuVo,redisTo);
//3.设置上当前商品的秒杀时间信息
redisTo.setStartTime(session.getStartTime().getTime());
redisTo.setEndTime(session.getEndTime().getTime());
redisTo.setRandomCode(token);
String jsonString = JSON.toJSONString(redisTo);
ops.put( seckillSkuVo.getPromotionSessionId().toString()+"_"+seckillSkuVo.getSkuId().toString(),jsonString);
RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMPHORE + token);
semaphore.trySetPermits(seckillSkuVo.getSeckillCount());
}
});
});
}
jdk8的时间新特性,博客之前也写过:https://www.cnblogs.com/dalianpai/p/12609438.html
@Override
public List<SeckillSessionEntity> lates3DaySession() {
List<SeckillSessionEntity> list = this.list(new QueryWrapper<SeckillSessionEntity>().between("start_time", startTime(), endTime()));
if(list!=null && list.size()>0){
List<SeckillSessionEntity> collect = list.stream().map(session -> {
Long id = session.getId();
List<SeckillSkuRelationEntity> relationEntities = seckillSkuRelationService.list(new QueryWrapper<SeckillSkuRelationEntity>().eq("promotion_session_id",id));
System.out.println(relationEntities);
session.setRelationSkus(relationEntities);
return session;
}).collect(Collectors.toList());
return collect;
}
return null;
}
public String startTime(){
LocalDate now = LocalDate.now();
LocalTime min = LocalTime.MIN;
LocalDateTime start = LocalDateTime.of(now, min);
String format = start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return format;
}
public String endTime(){
LocalDate now = LocalDate.now();
LocalDate localDate = now.plusDays(2);
LocalDateTime of = LocalDateTime.of(localDate, LocalTime.MAX);
String format = of.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return format;
}