.net core分布式事务落地(2)-最终一致性方案落地(DotNetCore.CAP)
使用DotNetCore.CAP解决分布式事务
目录:
- 方案简介
- 方案流程图
- 环境搭建
- 环境依赖
- 环境配置
- 代码实现
- 数据库初始化
- 创建应用程序
- 运行应用程序
- 结果
1. 方案简介
针对CAP事务,在本文中主要介绍.net core是如何实现最终一致性。整个方案,主要是基于 开源项目 DotNetCore.CAP +RabbitMQ+Mysql来实现的。
首先介绍下DotNetCore.CAP ,该项目是.net core的一个用于实现分布式事务(最终一致性)的开源项目,其项目集成了:
- 队列:RabbitMQ、AmazonSQS、RedisStreams
- 数据库本地消息表支持:Mysql、SqlServer、PostgreSql、MongoDB。
- 同时还支持AzureServiceBus、NATS等云服务消息总线。
2. 方案流程图

3. 环境搭建
3.1环境依赖:
1. docker,安装MySql8、RabbitMQ集群
2. 程序运行环境:.net 5
3.2 环境配置
1. docker安装mysql8,如果电脑上已经有了mysql,那跳过这个步骤。
运行docker命令:docker run --name mysqlServer --restart=always -p 6031:3306 -e MYSQL_ROOT_PASSWORD=pwd -d mysql --lower_case_table_names=1
2. 安装RabbitMQ集群,本次项目将安装三个rabbitmq:
docker run -d --hostname rabbit1 --name myrabbit1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management docker run -d --hostname rabbit2 --name myrabbit2 -p 5673:5672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management docker run -d --hostname rabbit3 --name myrabbit3 -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.6.15-management
3. 设置RabbitMQ集群
#设置节点1:
docker exec -it myrabbit1 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl start_app exit
#设置节点2,加入到集群:
docker exec -it myrabbit2 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl join_cluster --ram rabbit@rabbit1 rabbitmqctl start_app exit
#设置节点3,加入到集群:
docker exec -it myrabbit3 bash rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl join_cluster --ram rabbit@rabbit1 rabbitmqctl start_app exit
4. 结果

图:环境配置成功示意图
4. 代码实现
本次介绍主要是结合场景:一个用户支付订单,调用支付,并且更新订单数据。因订单和支付分别属于两个不同系统,所以基于这个场景来进行分布式事务的演示。
示例代码已上传到码云:https://gitee.com/fengwuyan/distributed-transaction-demo
4.1 数据库初始化
打开doc文件夹下的数据库脚本文件夹,运行两个sql脚本,会创建两个数据库,分别是OrderService和PaymentService。

图:数据库初始化
4.2 创建应用程序
1. 第一步:
使用vs分别创建OrderService和PaymentService的WebApi程序,以及创建一个EF.Model访问数据库类库程序。

图:程序目录结构
2. 第二步:
因本次演示节省时间,订单系统和支付系统都使用同一个ef项目。引用EFCore及EF mysql的支持包。创建order和payment表对应的实体类,及efcontext实现类

图:EF.Model
3.第三步:
在OrderService和PaymentService项目中引用以下包:
-
- DotNetCore.CAP
- DotNetCore.CAP.MySql
- DotNetCore.CAP.RabbitMQ
并且在StartUp中配置CAP及EF类:

图:WebApi的CAP及EF配置
4.第四步:
在PaymentService创建控制器:PaymentController,注入CAP发布消息对象,及EF访问类和其他对象等

图:注入支付控制器所需对象
5.第五步:
创建一个支付方法,在更新完支付信息之后,使用cap推送支付成功消息

图:支付方法
6.第六步:
在OrderService创建控制器:OrderController,注入CAP发布消息对象,及EF访问类和其他对象等

图:订单系统控制器对象注入
7.第七步:
创建一个消费消息的方法,用户处理本地消息表数据,完成订单更新,特性标签CapSubscribe 用于指示该方法处理消息队列的名称,该名称跟支付系统内发送消息的名称相同。

4.3 运行程序
1. 第一步
在orderservice程序根目录运行cmd命令:dotnet run --urls http://*:2001,将orderservice成功运行起来

图:orderservice运行图
2.第二步:
在paymentservice程序根目录运行cmd命令:dotnet run --urls http://*:2002 ,将paymentservice成功运行起来

3.第三步:
使用postman工具,发送post请求,http://127.0.0.1:2002/api/Payment/apply?paymentId=1 然后成功的发现,报错了,错误的大致意思是,你传入的参数不是MysqlParameter。

最终,没办法,只能把源码下下来调试,最终发现CAP 默认MySql使用的是用的MysqlConnector,而EF默认用的是Mysql.Data包,这两个包都有MysqlParameter等对象,但是不是同一个,于是只能对源码进行修改,将MysqlConnector包替换成MySql.Data包。修改项目引用,CAP的包都引用本地的。

然后重新启动项目,访问2002的apply接口。
4.4 结果
支付成功,也成功的更新了订单

图:程序运行结果图
--------------------------------------------------------结束语---------------------------------------------------------------
相信大家,经过整个了解,对与如何解决分布式事务,已经有了一定的了解,在此祝大家技术牛哄哄。

浙公网安备 33010602011771号