前言
書接上文,上文我們已經把秒殺的一個預減庫存的操作都已經實現了,
而且是使用redis作爲我們的第一道防線
而且在上個章節中我們知道一個秒殺有兩道重點線
java代碼優化方案3(redis預減庫存,redis標記商品)
一,去判斷這個商品是否還有庫存,去判斷這個用戶是否已經秒殺成功過。
這些如果沒有上個章節的知識的話,我估計大部分的人還是會單獨的去佔用數據庫的資源來進行查詢判斷。
而上個章節剛好也就使用了redis作爲緩存的第一道防線來爲數據庫減少了壓力,解決了這一問題
二、商品有庫存,用戶沒秒過殺,接下來要幹嘛?
當然是需要減少庫存,生成訂單表,生成訂單詳細表。(今天的主題)
1、Rabbitmq的配置文件(springboot)
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
properties配置文件的配置
#rabbitmq
spring.rabbitmq.host=192.168.47.137
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
#消費者數量
spring.rabbitmq.listener.simple.concurrency= 10
spring.rabbitmq.listener.simple.max-concurrency= 10
#消費者每次從隊列獲取的消息數量
spring.rabbitmq.listener.simple.prefetch= 1
#消費者自動啓動
spring.rabbitmq.listener.simple.auto-startup=true
#消費失敗,自動重新入隊
spring.rabbitmq.listener.simple.default-requeue-rejected= true
#啓用發送重試
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=1000
spring.rabbitmq.template.retry.max-attempts=3
spring.rabbitmq.template.retry.max-interval=10000
spring.rabbitmq.template.retry.multiplier=1.0
消息類(MiaoshaMessage )
public class MiaoshaMessage{
private MiaoshaUser user;
private long goodsId;
public MiaoshaUser getUser() {
return user;
}
public void setUser(MiaoshaUser user) {
this.user = user;
}
public long getGoodsId() {
return goodsId;
}
public void setGoodsId(long goodsId) {
this.goodsId = goodsId;
}
}
配置類(MQConfig )
@Configuration
public class MQConfig {
public static final String MIAOSHA_QUEUE = "miaosha.queue";
public static final String QUEUE = "queue";
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";
public static final String HEADER_QUEUE = "header.queue";
public static final String MIAOSHA_EXCHANGE = "miaosha.exchange";
public static final String TOPIC_EXCHANGE = "topicExchage";
public static final String FANOUT_EXCHANGE = "fanoutxchage";
public static final String HEADERS_EXCHANGE = "headersExchage";
/**
* Direct模式 交換機Exchange
* */
@Bean
public Queue queue() {
return new Queue(QUEUE, true);
}
/**
* Topic模式 交換機Exchange
* */
}
2、Rabbitmq的下單
代碼:
@RequestMapping(value="/do_miaosha", method=RequestMethod.POST)
@ResponseBody
public Result<Integer> miaosha(HttpServletRequest request, HttpServletResponse response,
Model model, MiaoshaUser user,
@RequestParam("goodsId")long goodsId) {
model.addAttribute("user", user);
if(user == null) {//判斷用戶是否有cookie
return Result.error(CodeMsg.SESSION_ERROR);
}
//內存標記,減少redis訪問
boolean over = localOverMap.get(goodsId);
if(over) {//商品的狀態爲不可秒殺就展示
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//預減庫存
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10
if(stock < 0) {//如果庫存只有-1就進入這裏面,因爲上面已經減去了一份庫存
localOverMap.put(goodsId, true);//並且把這個對應的商品狀態改爲true(不可秒殺了)
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//判斷有無秒殺成功過後的一個redis緩存記錄
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);//在裏面不是使用數據庫,而是redis
if(order != null) {//如果有則展示不可以多次秒殺
return Result.error(CodeMsg.REPEATE_MIAOSHA);
}
//入隊
MiaoshaMessage mm = new MiaoshaMessage();
mm.setUser(user);
mm.setGoodsId(goodsId);
sender.sendMiaoshaMessage(mm);
return Result.success(0);//排隊中
}
圖解:
3、消費者的發送消息(MQSender)
MQSender
@Service
public class MQSender {
private static Logger log = LoggerFactory.getLogger(MQSender.class);
@Autowired
AmqpTemplate amqpTemplate ;
public void sendMiaoshaMessage(MiaoshaMessage mm) {
String msg = RedisService.beanToString(mm);
log.info("send message:"+msg);
amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE, msg);
}
}
圖解:
4、服務者處理消息(MQReceiver)
receive
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = MQConfig.MIAOSHA_QUEUE,
durable = "true"),
exchange = @Exchange(value = MQConfig.MIAOSHA_EXCHANGE,
durable = "true",
type = "topic",
ignoreDeclarationExceptions = "true"),
key = "miaosha.#"
)
)
public void receive(String message) {
log.info("receive message:" + message);
MiaoshaMessage mm = RedisService.stringToBean(message, MiaoshaMessage.class);
MiaoshaUser user = mm.getUser();
long goodsId = mm.getGoodsId();
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
int stock = goods.getStockCount();
if (stock <= 0) {
return;
}
//判斷是否已經秒殺到了(不是調用數據庫的線,而是直接從redis中判斷)
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
return;
}
//減庫存 下訂單 寫入秒殺訂單
miaoshaService.miaosha(user, goods);
}
}
圖解:
下訂單操作:
reduceStock();(減庫存)
createOrder();(增加訂單表和秒殺訂單表)
後言
記得要開啓Rabbitmq服務和改配置文件
並且要了解Rabbitmq的基本知識點。
項目代碼:
鏈接:https://pan.baidu.com/s/1lLuT_BdfpdYxuKSGe_TQqw
提取碼:iqeb