【RabbitMQ】03--拼多商城小项目实践

一,业务分析

1.背景

当用户下订单时,我们的业务系统直接与数据库通信,把订单保存到数据库中,当系统流量突然激增,大量的订单压力,会拖慢业务系统和数据库系统,我们需要应对流量峰值,让流量曲线变得平缓,如下图
【RabbitMQ】03--拼多商城小项目实践_第1张图片

2.实现

订单存储的解耦
为了进行流量削峰,我们引入 rabbitmq 消息队列,当购物系统产生订单后,可以把订单数据发送到消息队列;而订单消费者应用从消息队列接收订单消息,并把订单保存到数据库
【RabbitMQ】03--拼多商城小项目实践_第2张图片
这样,当流量激增时,大量订单会暂存在rabbitmq中,而订单消费者可以从容地从消息队列慢慢接收订单,向数据库保存。

二,准备工作

因为是事先写好的项目,所以直接导入就好。

1.项目导入

1)先将pd-web放在对应的父项目文件夹下
【RabbitMQ】03--拼多商城小项目实践_第3张图片

2)将准备好的pom.xml文件直接拖入idea
【RabbitMQ】03--拼多商城小项目实践_第4张图片
3)在编辑器内右键 --> add as maven project
【RabbitMQ】03--拼多商城小项目实践_第5张图片
【RabbitMQ】03--拼多商城小项目实践_第6张图片

2.导入数据库

由于数据库过大,所以可事先增加MySQL缓存大小

set global max_allowed_packet=100000000;
set global net_buffer_length=100000;
SET GLOBAL interactive_timeout=28800000;
SET GLOBAL wait_timeout=28800000;

使用可视化工具导入即可

3.添加ampb依赖

<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-amqpartifactId>
dependency>

4.在application.yml中添加RabbitMQ相关配置

【RabbitMQ】03--拼多商城小项目实践_第7张图片

5.选择工作目录

因为有些是需要加载静态资源,所以选择静态目录
【RabbitMQ】03--拼多商城小项目实践_第8张图片

6.在启动类中准备队列的参数

package com.pd;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@MapperScan("com.pd.mapper")
public class RunPdAPP{
     
	
	public static void main(String[] args) {
     
		SpringApplication.run(RunPdAPP.class, args);
	}

	/*
	新建 Queue 实例,用来封装队列的参数,
	Rabbitmq的自动配置类会自动发现 Queue 实例,
	根据其中的参数,连接服务器创建队列
	import org.springframework.amqp.core.Queue;
	 */
	@Bean
	public Queue orderQueue() {
     
		return new Queue("orderQueue",true,false,false);
	}

}

三,向RabbitMQ发送订单

在订单业务实现类中,取出原先提交订单的数据库操作,转换为将订单传送到RabbitMQ中

/*
	在 RabbitAutoConfiguration 中自动创建了AmqpTemplate实例,
	这里直接注入
	 */
	@Autowired
	private AmqpTemplate t;
	
	public String saveOrder(PdOrder pdOrder) throws Exception {
     
		String orderId = generateId();
		pdOrder.setOrderId(orderId); // orderId,addId,userId,itemIdList
		// 转换并发送
		// 自动把数据变成 byte[] 数组,再发送
		t.convertAndSend("orderQueue", pdOrder);
		return orderId;
	}

四,创建消费者业务

1)在同目录下复制pd-web的项目取名pd-web-consumer作为消费者服务
2)修改pom.xml中artifactId
3)在xml中修改端口配置

五,将RabbitMQ中数据传入数据库

1.自动获取队列信息

在pd-web-consumer创建OrderConsumer

package com.pd;

import com.pd.pojo.PdOrder;
import com.pd.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 自动创建实例
 * 自动注册成为消费者
 * 自动将消息传递到 @RabbitHandler方法
 */
@Component
@RabbitListener(queues = "orderQueue")
public class OrderConsumer {
     
    @Autowired
    private OrderService orderService;
    //配合@RabbitListener,用来指定处理消息的方法
    //@RabbitHandler注解只能有一个,不能有多个
    @RabbitHandler
    public void receive(PdOrder pdOrder) throws Exception {
     
        orderService.saveOrder(pdOrder);
        System.out.println("----------------------------订单已保存");
    }
}

2.存数据库

在pd-web-consumer中订单业务实现类中将订单存入数据库

public String saveOrder(PdOrder pdOrder) throws Exception {
     
		 String orderId = pdOrder.getOrderId();
		 PdShipping pdShipping = pdShippingMapper.selectByPrimaryKey(pdOrder.getAddId());
		 pdOrder.setShippingName(pdShipping.getReceiverName());
		 pdOrder.setShippingCode(pdShipping.getReceiverAddress());
		 pdOrder.setStatus(1);//
		 pdOrder.setPaymentType(1);
		 pdOrder.setPostFee(10D);
		 pdOrder.setCreateTime(new Date());

		 double payment = 0;
		 List<ItemVO> itemVOs = selectCartItemByUseridAndItemIds(pdOrder.getUserId(), pdOrder.getItemIdList());
		 for (ItemVO itemVO : itemVOs) {
     
		 	PdOrderItem pdOrderItem = new PdOrderItem();
		 	String id = generateId();
		 	//String id="2";
		 	pdOrderItem.setId(id);
		 	pdOrderItem.setOrderId(orderId);
		 	pdOrderItem.setItemId("" + itemVO.getPdItem().getId());
		 	pdOrderItem.setTitle(itemVO.getPdItem().getTitle());
		 	pdOrderItem.setPrice(itemVO.getPdItem().getPrice());
		 	pdOrderItem.setNum(itemVO.getPdCartItem().getNum());

		 	payment = payment + itemVO.getPdCartItem().getNum() * itemVO.getPdItem().getPrice();
		 	pdOrderItemMapper.insert(pdOrderItem);
		 }
		 pdOrder.setPayment(payment);
		 pdOrderMapper.insert(pdOrder);
		return orderId;
	}

六,总结

我们首先在系统服务中,我们不是直接点击确定后,直接将订单存入数据库,当订单量大的时候,数据库一时肯定是吃不消的,所有我们在系统中将订单信息发送到消息队列中,这里使用的RabbitMQ;然后再创建一个消费者服务,专门进行订单存入数据库的操作,消息队列发送消息肯定是均衡,一次达到流量削峰的效果。

你可能感兴趣的:(RabbitMQ,rabbitmq,分布式)