文章目录
1.概述
假设我们向商城的订单系统下订单,在短时间内突然产生大量订单的情况下,直接向数据库存储数据可能会导致数据库崩溃;
但是如果我们使用RabbitMQ消息服务进行接收的话,订单会在RabbitMQ处进行排队等待消费者进行处理,一个一个的接收进行处理然后存储到数据库中,避免因突增的大量访问数据而导致系统崩溃;
这就是流量削峰,将短时间内突增的大量数据访问造成的流量峰值处理时间进行拉长,消除其流量峰值;
RabbitMQ数据吞吐量是非常大的,可以轻松承担数据库无法承担的压力,当RabbitMQ也无法承担压力时,可以选择增加服务器,或使用阿里,腾讯的RabbitMQ,腾讯的RabbitMQ号称可以承担万亿级别的流量;
当大量数据排队时,可能会导致处理时间过长的问题,此时可以增加消费者来进行数据的多线程处理;
2.项目准备
2.1 导入项目
找i到gitee仓库cheapter-six项目中file文件夹中的pd-web项目压缩文件,拉取到本地后解压到rabbitmq目录下:

在文件夹中直接将pom.xml文件拖拽到IDEA编辑区域中,修改springboot版本为2.3.2.RELEASE;
编辑完成后,直接在编辑区域右键–Add Maven Project以maven方式导入此工程:

2.2 导入数据库
在SQLYog左侧地址栏空白处右键,选择从SQL转储文件导入数据库,选择pd-web目录下的pd.sql文件进行导入:

如果导入失败可能是因为数据库缓存不够引起的,可以增大数据库缓存后重新执行;导入完成后,检查表中是否存在测试数据,删除所有测试数据:
# 删除用户数据
delete from pd_user
# 删除订单数据
delete from pd_order
delete from pd_order_item
2.3启动项目
- 右键点击RunApp,运行项目
- 在启动配置中,配置working directory,设置称pd-web文件夹的路径
- 重启RunApp
- 访问http://localhost,如果看到浏览器在下载需要清理浏览器缓存后重新访问;


2.4 测试项目基础功能
- 测试用户注册


- 添加收货地址

注意除必填项外,其他内容需保证填写正确,项目为测试项目,缺少许多校验程序,填写错误也可以添加成功,但会影响后续功能;
- 创建订单
点击商品后,将其加入购物车,在购物车中选中商品点击去结算,在确认订单页面点击确认并付款,此时我们的订单就已经创建好了:



此时保存在数据库中的订单就是一个未付款的订单;
2.5 数据库操作代码注释
我们将项目中,订单数据库操作的相关代码全部注释,使用RabbitMQ进行数据的处理:

3.订单发送到RabbitMQ
我们对项目进行改造,使订单不执行数据库操作,而是通过RabbitMQ进行存储:

3.1 依赖添加
在pom.xml文件中添加RabbitMQ依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
3.2 配置文件添加连接配置
在application.yml配置文件中添加连接配置:
rabbitmq:
host: 192.168.64.140
port: 5672
username: admin
password: admin
3.3 代码实现
3.3.1 队列参数实现
因为启动类本身就是一个自动配置类,所以我们直接在启动类中(或者自定义自动配置类)配置队列参数:
- 因为订单是不允许丢失的,所以我们使用持久队列
- 为了考虑订单的处理效率,所以设置非独占队列
- 因为订单的不可丢失特性,所以我们设置队列不可自动删除
//创建对象,封装队列使用的参数,配置使用的队列
//orderQueue:持久,非独占,不自动删除
@Bean
public Queue orderQueue(){
return new Queue("orderQueue",true,false,false);
}
注意这里使用的Queue对象是spring封装的Queue对象,不是原生的RabbitMQ的Queue对象;
3.3.2 订单处理方法实现
我们注入AmqpTemplate工具:
@Autowired
private AmqpTemplate amqpTemplate;
使用AmqpTemplate封装工具发送订单即可:
/**
* 使用AmqpTemplate对象实现消息发送
* 将订单转换为byte数组并发送到orderQueue
* 订单实例会自动被序列化成 byte[] 数组再进行转发
* PdOrder已实现序列化接口
* */
amqpTemplate.convertAndSend("orderQueue",pdOrder);
3.4 订单发送测试
重新启动项目后,创建新的订单:

订单创建完成后,此时数据库中并没用我们新的订单数据,订单数据被存储到了RabbitMQ队列中,我们在RabbitMQ控制台的队列中点击我们刚创建的队列:

进入队列后,在队列中点击getMessage即可查看订单消息:

因为序列化的原因,数据显示是byte类型的字节码值,不是按照字符类型显示的,所以我们无法直接查看;
4.消费者执行数据库操作
4.1 项目准备
我们在文件夹中,将pd-web文件夹复制一份并命名为pd-web-consumer

将pd-web-consumer文件夹中的pom.xml文件拖拽到IDEA中修改artifactId为当前文件夹名称:

修改完成后,在当前界面空白处右键选择 Add as Maven Projecte 进行导入:

修改项目的端口为81:

我们复制的项目中,已经对RabbitMQ的依赖,连接配置,使用的队列等进行了配置,复制后直接使用即可;
4.2 订单消费者创建
4.2.1 新建消费者类
我们获取队列中的消息,调用接口实现类保存订单:
- 通过注解配置,从orderQueue 接收订单;
- 调用OrderServiceImpl.saveOrder()存储订单;
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;
@Component
@RabbitListener(queues = "orderQueue") //通过注解配置从orderQueue接收订单消息
public class OrderConsumer {
@Autowired
private OrderService orderService;
/**
* 自定义处理消息的方法
* 传入参数为接收队列中的参数
* @RabbitHandler注解配合RabbitListener用来指定处理消息的方法
* 一个类中只能有一个@RabbitHandler注解描述的方法
* */
@RabbitHandler
public void recive(PdOrder order) throws Exception {
orderService.saveOrder(order);
System.out.println("订单已保存!!");
}
}
4.2.2 调整OrderServiceImpl
因为我们是复制的项目,数据库操作代码此前已经被注释,这里我们需要打开注释代码,并且注释注入的AmqpTemplate实例;因为我们在前边的操作已经生成了orderId,所以这里要将生成orderId的代码也注释掉并且将此前生成的orderId获取到:

4.3 测试
我们启动项目进行测试,在项目启动时,我们就可以看到控制台打印的订单保存信息:
需要同时启动生产者和消费者,并且生产者要正常创建队列;

并且在数据库中我们也可以看到记录数据的存储;
5.总结
类似于这种商城的订单系统,将直接发送到数据库的订单信息先发送到RabbitMQ,然后再排队慢慢处理,可以有效的解决流量突增的情况,这里一般使用简单模式或工作模式;
我们使用封装的AmqpTemplate封装工具转换并发送消息,使用@RabbitListener注解进行消息的接收;

1028

被折叠的 条评论
为什么被折叠?



