秒杀优化

pull/8/head
czk 2024-05-02 19:29:55 +08:00
parent 7c67d8de5b
commit 387c5e3db3
16 changed files with 130 additions and 100 deletions

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mall.common.domain.OrderItemEntity;
import com.mall.server.config.DelayConfig;
import com.mall.server.config.MqConfig;
import com.mall.server.constant.SpikesConstant;
import com.mall.server.service.OrderItemService;
import com.rabbitmq.client.Channel;
@ -48,7 +49,39 @@ public class SpikesMonitor {
try {
channel.basicAck(deliveryTag,false);
} catch (IOException e) {
throw new RuntimeException(e);
try {
if(deliveryTag<3){
Thread.sleep(3000);
channel.basicNack(deliveryTag,false,true);
}else {
channel.basicNack(deliveryTag,false,false);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
@RabbitListener(queues = MqConfig.DXQUEUE)
public void orderConsumer(String meg, Message message, Channel channel){
log.info("下订单"+meg);
long deliveryTag = message.getMessageProperties().getDeliveryTag();
orderItemService.save(JSON.parseObject(meg,OrderItemEntity.class));
try {
channel.basicAck(deliveryTag,false);
} catch (IOException e) {
try {
if(deliveryTag<3){
Thread.sleep(3000);
channel.basicNack(deliveryTag,false,true);
}else {
channel.basicNack(deliveryTag,false,false);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -1,6 +1,5 @@
package com.mall.server.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mall.common.constant.TokenConstants;
@ -14,6 +13,7 @@ import com.mall.common.result.Result;
import com.mall.common.utils.IdUtils;
import com.mall.common.utils.StringUtils;
import com.mall.server.config.DelayConfig;
import com.mall.server.config.MqConfig;
import com.mall.server.constant.SpikesConstant;
import com.mall.server.domain.SkuEntity;
import com.mall.server.domain.SpikesEntity;
@ -21,12 +21,10 @@ import com.mall.server.mapper.SpikesMapper;
import com.mall.server.service.OrderItemService;
import com.mall.server.service.SkuService;
import com.mall.server.service.SpikesService;
import com.mall.server.service.SpuService;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -39,7 +37,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
*serviceImpl
* serviceImpl
*/
@Service
public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
@ -69,14 +67,15 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
/**
*
*
* @param spikesRequest
* @return
*/
@Transactional
@Override
public Result add(SpikesRequest spikesRequest) {
if(spikesRequest.getCreateTime().getMinutes()%60!=0){
throw new BizException(500,"不是整点");
if (spikesRequest.getCreateTime().getMinutes() % 60 != 0) {
throw new BizException(500, "不是整点");
}
//一天后的0点
Date date = Date.from(
@ -84,8 +83,8 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
.withSecond(0).withNano(0)
.plusDays(1).atZone(ZoneId.systemDefault()).toInstant()
);
if(spikesRequest.getCreateTime().compareTo(date)<0){
throw new BizException(500,"时间必须是第二天0点");
if (spikesRequest.getCreateTime().compareTo(date) < 0) {
throw new BizException(500, "时间必须是第二天0点");
}
//秒杀表信息
int spikesId = spikesMapper.insert(
@ -103,7 +102,7 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
);
//修改sku商品信息
skuService.updateBatchById(
spikesRequest.getSkuList().stream().map(c->
spikesRequest.getSkuList().stream().map(c ->
SkuEntity.builder()
.id(c.getSkuId())
.inventoryRestrict(c.getInventoryRestrict())
@ -137,26 +136,27 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
.endTime(spikesRequest.getEndTime()).build()
).collect(Collectors.toList());
//后期存入redis放入查询列表中
activitySkuVoList.forEach(c->{
activitySkuVoList.forEach(c -> {
//redis秒杀信息存在时间
long expire = (c.getEndTime().getTime() - System.currentTimeMillis()) / 60000;
redisCache.setCacheObject(SpikesConstant.SPIKES_SKUID +c.getId(),c,expire, TimeUnit.MINUTES);
redisCache.setCacheObject(SpikesConstant.SPIKES_SKUID + c.getId(), c, expire, TimeUnit.MINUTES);
});
return Result.success(true,"添加秒杀成功");
return Result.success(true, "添加秒杀成功");
}
/**
*
*
* @param skuId
* @return
*/
@Override
public Result spike(Long skuId) {
UserInfo login = getLogin();
if(redisCache.hasKey("spike_"+login.getId()+skuId)){
throw new BizException(500,"禁止重复抢购欧");
if (redisCache.hasKey("spike_" + login.getId() + skuId)) {
throw new BizException(500, "禁止重复抢购欧");
}
redisCache.setCacheObject("spike_"+login.getId()+skuId,IdUtils.genId().toString(),1L,TimeUnit.MINUTES);
redisCache.setCacheObject("spike_" + login.getId() + skuId, IdUtils.genId().toString(), 1L, TimeUnit.MINUTES);
SkuEntity skuEntity = skuService.getOne(
new LambdaQueryWrapper<SkuEntity>()
.eq(skuId != null, SkuEntity::getId, skuId)
@ -165,16 +165,15 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
new LambdaQueryWrapper<SpikesEntity>()
.eq(skuEntity.getSpikesId() != null, SpikesEntity::getSpikesId, skuEntity.getSpikesId())
);
if(spikesEntity.getCreateTime().compareTo(new Date())>0 || spikesEntity.getEndTime().compareTo(new Date())<0){
throw new BizException(500,skuEntity.getName()+"该商品不在抢购时间内");
if (spikesEntity.getCreateTime().compareTo(new Date()) > 0 || spikesEntity.getEndTime().compareTo(new Date()) < 0) {
throw new BizException(500, skuEntity.getName() + "该商品不在抢购时间内");
}
RSemaphore semaphore = redissonClient.getSemaphore(SpikesConstant.SPIKES_INVENTORY + skuId);
if(!semaphore.tryAcquire(1)){
throw new BizException(500,"系统繁忙,商品已抢购完");
if (!semaphore.tryAcquire(1)) {
throw new BizException(500, "系统繁忙,商品已抢购完");
}
String orderSn = IdUtils.genId();
orderItemService.save(
OrderItemEntity.builder()
OrderItemEntity orderItem = OrderItemEntity.builder()
.userId(login.getId())
.orderSn(orderSn)
.skuId(skuId)
@ -185,22 +184,28 @@ public class SpikesServiceImpl extends ServiceImpl<SpikesMapper, SpikesEntity>
// .couponAmount()
// .integrationAmount()
.realAmount(skuEntity.getActivityPrice())
.status(0).build()
);
.status(0).build();
//异步下订单
rabbitTemplate.convertAndSend(MqConfig.DXEXCHANGE, MqConfig.ROUTINGKEY, orderItem.toString(),
message -> {
message.getMessageProperties().setMessageId(IdUtils.genId());
return message;
});
rabbitTemplate.convertAndSend(
DelayConfig.EXCHANGE, DelayConfig.ROUKEYCZK, skuId + "," +orderSn ,
DelayConfig.EXCHANGE, DelayConfig.ROUKEYCZK, skuId + "," + orderSn,
message -> {
message.getMessageProperties().setMessageId(IdUtils.genId());
return message;
}
);
return Result.success(skuId,"下单成功");
return Result.success(skuId, "下单成功");
}
public UserInfo getLogin(){
public UserInfo getLogin() {
String token = request.getHeader(TokenConstants.TOKEN);
if (StringUtils.isBlank(token)){
throw new BizException(401,"未登录");
if (StringUtils.isBlank(token)) {
throw new BizException(401, "未登录");
}
UserInfo userInfo = redisCache.getCacheObject(TokenConstants.TOKEN + token);
return userInfo;