项目技术

SpringCloudAlibaba Nacos Seata Mysql Feign

代码地址

这个代码我是基于 图灵学院 的项目改的, 原来的项目代码演示下单,扣库存,扣账户金额,一系列的业务代码,我感觉太臃肿了,其实分布式事务无外乎就是多个服务分别进行写操作多个mysql库,要么同时写入成功要么同时写入失败.
我把业务代码都删了,直接用最简单的方式演示多个微服务分别操作不同的数据库,要么同时insert成功,要么触发异常都不会写进数据,不会出现一个库insert进去数据,一个库没有insert进去数据的情况

代码地址:
https://gitee.com/zjj19941/ZJJ_Neaten5.10/tree/master/ZJJ_Seata/springcloud-nacos-feign-seata

代码说明

执行sql脚本

项目里面有个db.sql文件,自己自行创建两个数据库,然后根据下面图片去执行sql脚本, 在seata_storage库里面创建undo_log表和storage_tbl表, 在 seata_order库里面创建undo_log表和order_tbl表

image.png

registry.conf

  1. registry {
  2. type = "nacos"
  3. nacos {
  4. serverAddr = "zjj101:8848"
  5. namespace = ""
  6. cluster = ""
  7. group = "SEATA_GROUP"
  8. }
  9. }
  10. config {
  11. type = "nacos"
  12. nacos {
  13. serverAddr = "zjj101:8848"
  14. namespace = "7c475dad-93cb-4740-941f-1a6636addd93"
  15. group = "SEATA_GROUP"
  16. }
  17. }

seata 注册中心配置

registry 的type直接选nacos,代表从nacos连接Seata-Server,我都nacos上的public组里面有一个seata-searver,分组名称是SEATA_GROUP,所以 namespace 直接配置”” ,或者删掉不配置也行,serverAddr 指向的是你nacos服务的地址,我这里是zjj101:8848, 我不是集群模式 cluster 直接是””,或者不配置cluster 也行, group配置SEATA_GROUP要和nacos控制面板的seata的分组名称保持一致,不然找不到seata服务.

nacos {
serverAddr = “zjj101:8848”
namespace = “”
cluster = “”
group = “SEATA_GROUP”
}
image.png

seata的config配置

config {
type = “nacos”
nacos {
serverAddr = “zjj101:8848”
namespace = “7c475dad-93cb-4740-941f-1a6636addd93”
group = “SEATA_GROUP”
}

type=nacos代表seata从nacos上面读取配置, 问这里seata配置单独是放在了seata组里面的,不然配置放到public里面的话,太多了,有100多条,里面就是一些配置,这些配置是导进来的,如果没有导进来就看 https://www.yuque.com/docs/share/d13e525b-1e1b-4a42-8907-e0c9e7e00acb?# 《将seata默认配置导入到nacos配置列表中》 这个帖子,

image.png

nacos {
serverAddr = “zjj101:8848”
namespace = “7c475dad-93cb-4740-941f-1a6636addd93”
group = “SEATA_GROUP”
}

serverAddr = “zjj101:8848” 不用说了,就是配置nacos配置中心的地址
namespace 这个配置的参数就是配置中心的seata组的uuid串儿,image.png

  1. group = "SEATA_GROUP" 这个配置就是要和配置中心的Group配置保持一致<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/350923/1643794538461-9df8bd38-53b6-488d-8c44-0a27824a6cfb.png#clientId=u95fdd218-c152-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=690&id=ube2e1749&margin=%5Bobject%20Object%5D&name=image.png&originHeight=690&originWidth=1231&originalType=binary&ratio=1&rotation=0&showTitle=false&size=87940&status=done&style=none&taskId=ubc10e574-f00b-40d4-961a-070da82e64f&title=&width=1231)

事务组配置

org.springframework.cloud:spring-cloud-starter-alibaba-seataorg.springframework.cloud.alibaba.seata.GlobalTransactionAutoConfiguration类中,默认会使用 ${spring.application.name}-seata-service-group作为服务名注册到 Seata Server上,如果和service.vgroup_mapping配置不一致,会提示 no available server to connect错误

也可以通过配置 spring.cloud.alibaba.seata.tx-service-group修改后缀,但是必须和file.conf中或者nacos配置中心的配置保持一致

image.png

image.png自定义事务组名称需要与seata-server中的对应,具体事务组的作用,回来我稍后研究研究再补上,其实事务组概念我也不是太明白,我觉得就是类似于nacos的Group概念,就是资源隔离的概念,每个事务组可以配置不同的参数,这样更细化,我是这么理解的,如果理解有问题,你们指出来.

调用入口要有@GlobalTransactional注解

调用的地址是: http://localhost:8020/order/test01

image.png
com.tuling.order.service.impl.OrderServiceImpl#test01 方法是最上层的入口service方法,需要在这个方法上添加@GlobalTransactional注解,不然会出现分布式事务失效.
image.png

启动项目

直接启动OrderServiceApplication和StorageServiceApplication 这两个启动类,

启动完毕,发现nacos多了这两个服务

image.png

开始测试

正确的请求

Postman执行 post请求 : http://localhost:8020/order/test01 ,参数是{“count”:1}

image.png

执行成功,查看数据库.

发现两个库的表插入成功了,uuid都是ca835d04-8362-48f1-9b44-1e62acd5e0821643795815143
image.png

失败的请求

OrderService服务会先执行插入数据到order_tbl表操作,然后再调用StorageService服务准备插入数据到storage_tbl表操作, 在插入之前会触发下面的箭头指向的错误代码,.会抛出来ByZero异常出来

模拟业务失败,当count不是1的时候,这里会抛出ByZero异常出来,
image.png

此时数据库里面没有数据,之前测试的数据我已经清掉了
image.png

postman执行 post请求: http://localhost:8020/order/test01 参数是:{“count”:2}

image.png

执行完了发现报错

image.png

查看两个库的两张表,发现并没有新的数据,说明分布式事务发挥作用了

image.png