core分布式事务落地(2)-最终⼀致性⽅案落地(DotNetCore.CAP)
使⽤DotNetCore.CAP解决分布式事务
⽬录: 
1. ⽅案简介
2. ⽅案流程图
3. 环境搭建
1. 环境依赖
2. 环境配置
4. 代码实现
1. 数据库初始化
2. 创建应⽤程序
3. 运⾏应⽤程序
4. 结果
1. ⽅案简介
针对CAP事务,在本⽂中主要介绍 core是如何实现最终⼀致性。整个⽅案,主要是基于开源项⽬ DotNetCore.CAP +RabbitMQ+Mysql来实现的。
⾸先介绍下DotNetCore.CAP ,该项⽬是 core的⼀个⽤于实现分布式事务(最终⼀致性)的开源项⽬,其项⽬集成了:
1. 队列:RabbitMQ、AmazonSQS、RedisStreams
2. 数据库本地消息表⽀持:Mysql、SqlServer、PostgreSql、MongoDB。
3. 同时还⽀持AzureServiceBus、NATS等云服务消息总线。
2. ⽅案流程图
3. 环境搭建
3.1环境依赖:
1. docker,安装MySql8、RabbitMQ集
2. 程序运⾏环境: 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. 代码实现
  本次介绍主要是结合场景:⼀个⽤户⽀付订单,调⽤⽀付,并且更新订单数据。因订单和⽀付分别属于两个不同系统,所以基于这个场景来进⾏分布式事务的演⽰。  ⽰例代码已上传到码云:
  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访问类和其他对象等
图:注⼊⽀付控制器所需对象
mysql下载的vs库放在那个文件里  5.第五步:
    创建⼀个⽀付⽅法,在更新完⽀付信息之后,使⽤cap推送⽀付成功消息
图:⽀付⽅法
  6.第六步:
    在OrderService创建控制器:OrderController,注⼊CAP发布消息对象,及EF访问类和其他对象等
图:订单系统控制器对象注⼊
7.第七步:
    创建⼀个消费消息的⽅法,⽤户处理本地消息表数据,完成订单更新,特性标签CapSubscribe ⽤于指⽰该⽅法处理消息队列的名称,该名称跟⽀付系统内发送消息的名称相同。
  4.3 运⾏程序
1. 第⼀步
      在orderservice程序根⽬录运⾏cmd命令:dotnet run --urls ,将orderservice成功运⾏起来
图:orderservice运⾏图
    2.第⼆步:
      在paymentservice程序根⽬录运⾏cmd命令:dotnet run --urls ,将paymentservice成功运⾏起来
    3.第三步:
使⽤postman⼯具,发送post请求,然后成功的发现,报错了,错误的⼤致意思是,你传⼊的参数不是MysqlParameter。
      最终,没办法,只能把源码下下来调试,最终发现CAP 默认MySql使⽤的是⽤的MysqlConnector,⽽EF默认⽤的是Mysql.Data包,这两个包都有MysqlParameter 等对象,但是不是同⼀个,于是只能对源码进⾏修改,将MysqlConnector包替换成MySql.Data包。修改项⽬引⽤,CAP的包都引⽤本地的。
      然后重新启动项⽬,访问2002的apply接⼝。
  4.4 结果
    ⽀付成功,也成功的更新了订单
图:程序运⾏结果图
--------------------------------------------------------结束语---------------------------------------------------------------
  相信⼤家,经过整个了解,对与如何解决分布式事务,已经有了⼀定的了解,在此祝⼤家技术⽜哄哄。