一、MQ实现分布式事务,最简单的原理框架:
借助MQ的消息可靠传递,实现业务间解耦、事务强一致
1、>> 生产者发送消息做可靠性检查,确保消息真正投递出去;
2、>> 消费者做幂等,确保业务没有重复执行;
3、>> 消费者做异常重试,反复出错时需要捕捉异常并记录,以便手工干预;
二、场景实践:
场景
以支付宝转账到余额宝为例,在支付宝已经扣款成功的情况下,余额宝一定收到转账
>> 支付宝和余额宝是两个微服务;
>> 用户用支付宝转1万元到余额宝;
支付宝账户先扣除金额,MQ通知余额宝账户添加金额;
>> 支付宝账户表: update A set amount = amount - 10000 where userId = 1;
>> 余额宝账户表: update B set amount = amount + 10000 where userId = 1;
具体操作
1、创建队列
>> 创建一个持久化的队列,名称为money;
Durable(持久化保存),Transient(即时保存)。
2、 maven引入
(余额宝和支付宝两个服务都需要)
1
2
3
4
5
6
7
|
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
|
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
3、 添加配置
(余额宝和支付宝两个服务都需要)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
spring:
rabbitmq:
host: 192.168 . 222.26 #MQ地址
port: 5672 #MQ端口
username: admin #MQ用户名
password: admin #MQ密码
publisher-confirms: true #开启消息发送成功监听
publisher-returns: true #开启消息发送失败监听
listener:
simple:
acknowledge-mode: manual #手动提交事务
|
4 支付宝端代码编写
向支付宝账号扣款,同时发消息到队列中,通知余额宝账号金额更新
>> 配置MQ发送过程监听
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package cn.my.server.clientdemo.zhifu;
import javax.annotation.PostConstruct;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置MQ发送过程监听
* @author twotiger-wxm.
* @date 2020-3-3.
*/
@Configuration
public class RabbmitMqConfig {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
// 设置发送成功回调
rabbitTemplate.setConfirmCallback(initConfirmCallback());
// 设置发送失败回调
rabbitTemplate.setReturnCallback(initReturnCallback());
}
@Bean
public ReturnCallback initReturnCallback(){
return new FailedListener();
}
@Bean
public ConfirmCallback initConfirmCallback(){
return new SuccessListener();
}
}
|
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
<
|