• Spring Cloud Alibaba Seata 实现分布式事物


    Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案

    Seata 官网:https://seata.io/zh-cn/

    Spring Cloud Alibaba 官网:https://sca.aliyun.com/zh-cn/

    版本说明

    SpringBoot 版本 2.6.5

    SpringCloud 版本 2021.0.1

    SpringCloudAlibaba 版本 2021.0.1.0

    读者可以先看笔者前面写的文章《Spring Cloud Gateway 使用 Redis 限流使用教程》,里面有创建项目的详细版本说明,这篇seata的文章是在 gateway 限流的项目基础上创建的

    本文详细说明

    数据库服务器版本 mysql 8.0.25

    mybatis plus 版本 3.5.1

    nacos 版本 1.4.2

    seata 客户端版本 1.4.2

    seata 服务端版本 1.7.1,笔者在文章最后面会使用服务端版本 1.4.2 演示,这里使用1.7.1版本的原因是1.4.2版本没有web控制台,且配置没有1.7.1方便,目前1.7.1版本是最新版

    目录

    1、创建项目

    1.1、新建 maven 聚合项目 cloud-learn

    1.2、创建 account 服务

    1.3、创建 order 服务

    2、添加配置

    2.1、客户端配置

    2.2、服务端配置

    3、数据库建表

    3.1、seata 服务端建表

    3.2、seata 客户端建表

    4、运行测试

    5、Seata Server 1.4.2

    6、项目代码


    1、创建项目

    1.1、新建 maven 聚合项目 cloud-learn

    最外层父工程 cloud-learn 的 pom.xml

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>com.wsjzzcbqgroupId>
    7. <artifactId>cloud-learnartifactId>
    8. <version>1.0-SNAPSHOTversion>
    9. <modules>
    10. <module>gateway-learnmodule>
    11. <module>consumer-learnmodule>
    12. <module>sentinel-learnmodule>
    13. <module>seata-at-account-learnmodule>
    14. <module>seata-at-order-learnmodule>
    15. modules>
    16. <packaging>pompackaging>
    17. <repositories>
    18. <repository>
    19. <id>naxus-aliyunid>
    20. <name>naxus-aliyunname>
    21. <url>https://maven.aliyun.com/repository/publicurl>
    22. <releases>
    23. <enabled>trueenabled>
    24. releases>
    25. <snapshots>
    26. <enabled>falseenabled>
    27. snapshots>
    28. repository>
    29. repositories>
    30. <parent>
    31. <groupId>org.springframework.bootgroupId>
    32. <artifactId>spring-boot-starter-parentartifactId>
    33. <version>2.6.5version>
    34. <relativePath/>
    35. parent>
    36. <properties>
    37. <spring-cloud.version>2021.0.1spring-cloud.version>
    38. <spring-cloud-alibaba.version>2021.0.1.0spring-cloud-alibaba.version>
    39. <alibaba-nacos-discovery.veriosn>2021.1alibaba-nacos-discovery.veriosn>
    40. <alibaba-nacos-config.version>2021.1alibaba-nacos-config.version>
    41. <spring-cloud-starter-bootstrap.version>3.1.1spring-cloud-starter-bootstrap.version>
    42. <druid.version>1.1.17druid.version>
    43. <mysql.version>8.0.11mysql.version>
    44. <mybatis-plus.version>3.5.1mybatis-plus.version>
    45. properties>
    46. <dependencyManagement>
    47. <dependencies>
    48. <dependency>
    49. <groupId>org.springframework.cloudgroupId>
    50. <artifactId>spring-cloud-dependenciesartifactId>
    51. <version>${spring-cloud.version}version>
    52. <type>pomtype>
    53. <scope>importscope>
    54. dependency>
    55. <dependency>
    56. <groupId>com.alibaba.cloudgroupId>
    57. <artifactId>spring-cloud-alibaba-dependenciesartifactId>
    58. <version>${spring-cloud-alibaba.version}version>
    59. <type>pomtype>
    60. <scope>importscope>
    61. dependency>
    62. <dependency>
    63. <groupId>com.alibaba.cloudgroupId>
    64. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    65. <version>${alibaba-nacos-discovery.veriosn}version>
    66. dependency>
    67. <dependency>
    68. <groupId>com.alibaba.cloudgroupId>
    69. <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    70. <version>${alibaba-nacos-config.version}version>
    71. dependency>
    72. <dependency>
    73. <groupId>org.springframework.cloudgroupId>
    74. <artifactId>spring-cloud-starter-bootstrapartifactId>
    75. <version>${spring-cloud-starter-bootstrap.version}version>
    76. dependency>
    77. <dependency>
    78. <groupId>com.alibaba.fastjson2groupId>
    79. <artifactId>fastjson2artifactId>
    80. <version>2.0.40version>
    81. dependency>
    82. dependencies>
    83. dependencyManagement>
    84. <dependencies>
    85. <dependency>
    86. <groupId>org.projectlombokgroupId>
    87. <artifactId>lombokartifactId>
    88. dependency>
    89. dependencies>
    90. project>

    下面会创建2个服务 account 和 order,模拟用户下订单后扣减账户金额,服务间使用 feign 调用,因为 account 和 order 服务使用不同的数据库,因此产生分布式事物,使用 seata 解决

    seata 默认使用 AT 事物模型,本文讲解演示的就是 AT 事物模型,其他事物模型在后面的文章中讲解

    1.2、创建 account 服务

    创建子工程 seata-at-account-learn

    seata-at-account-learn pom 文件

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>cloud-learnartifactId>
    7. <groupId>com.wsjzzcbqgroupId>
    8. <version>1.0-SNAPSHOTversion>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>seata-at-account-learnartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>org.springframework.bootgroupId>
    15. <artifactId>spring-boot-starter-webartifactId>
    16. dependency>
    17. <dependency>
    18. <groupId>com.alibaba.cloudgroupId>
    19. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>com.alibaba.cloudgroupId>
    23. <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    24. dependency>
    25. <dependency>
    26. <groupId>com.alibaba.cloudgroupId>
    27. <artifactId>spring-cloud-starter-alibaba-seataartifactId>
    28. dependency>
    29. <dependency>
    30. <groupId>com.alibabagroupId>
    31. <artifactId>druid-spring-boot-starterartifactId>
    32. <version>${druid.version}version>
    33. dependency>
    34. <dependency>
    35. <groupId>mysqlgroupId>
    36. <artifactId>mysql-connector-javaartifactId>
    37. <version>${mysql.version}version>
    38. dependency>
    39. <dependency>
    40. <groupId>com.baomidougroupId>
    41. <artifactId>mybatis-plus-boot-starterartifactId>
    42. <version>${mybatis-plus.version}version>
    43. dependency>
    44. dependencies>
    45. <build>
    46. <plugins>
    47. <plugin>
    48. <groupId>org.springframework.bootgroupId>
    49. <artifactId>spring-boot-maven-pluginartifactId>
    50. plugin>
    51. plugins>
    52. build>
    53. project>

    启动类 SeataATAccountApplication

    1. package com.wsjzzcbq;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. /**
    6. * SeataATAccountApplication
    7. *
    8. * @author wsjz
    9. * @date 2023/10/14
    10. */
    11. @MapperScan(value = {"com.wsjzzcbq.mapper"})
    12. @SpringBootApplication
    13. public class SeataATAccountApplication {
    14. public static void main(String[] args) {
    15. SpringApplication.run(SeataATAccountApplication.class, args);
    16. }
    17. }

    实体类 Account

    1. package com.wsjzzcbq.bean;
    2. import lombok.Data;
    3. /**
    4. * Account
    5. *
    6. * @author wsjz
    7. * @date 2022/07/07
    8. */
    9. @Data
    10. public class Account {
    11. private Integer id;
    12. private String userId;
    13. private Integer money;
    14. }

     AccountMapper

    1. package com.wsjzzcbq.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.wsjzzcbq.bean.Account;
    4. /**
    5. * AccountMapper
    6. *
    7. * @author wsjz
    8. * @date 2023/10/13
    9. */
    10. public interface AccountMapper extends BaseMapper {
    11. }

    AccountService

    1. package com.wsjzzcbq.service;
    2. import com.baomidou.mybatisplus.extension.service.IService;
    3. import com.wsjzzcbq.bean.Account;
    4. /**
    5. * AccountService
    6. *
    7. * @author wsjz
    8. * @date 2023/10/13
    9. */
    10. public interface AccountService extends IService {
    11. String reduce(String userId, int money);
    12. }

    AccountServiceImpl

    1. package com.wsjzzcbq.service.impl;
    2. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
    3. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    4. import com.wsjzzcbq.bean.Account;
    5. import com.wsjzzcbq.mapper.AccountMapper;
    6. import com.wsjzzcbq.service.AccountService;
    7. import io.seata.core.context.RootContext;
    8. import org.springframework.stereotype.Service;
    9. /**
    10. * AccountServiceImpl
    11. *
    12. * @author wsjz
    13. * @date 2023/10/13
    14. */
    15. @Service
    16. public class AccountServiceImpl extends ServiceImpl implements AccountService {
    17. @Override
    18. public String reduce(String userId, int money) {
    19. String xid = RootContext.getXID();
    20. System.out.println(xid);
    21. UpdateWrapper up = new UpdateWrapper<>();
    22. String sql = "money = money - " + money;
    23. up.setSql(sql);
    24. up.eq("user_id", userId);
    25. this.update(up);
    26. return "ok";
    27. }
    28. }

    AccountController

    1. package com.wsjzzcbq.controller;
    2. import com.fasterxml.jackson.core.JsonProcessingException;
    3. import com.fasterxml.jackson.databind.ObjectMapper;
    4. import com.wsjzzcbq.bean.Account;
    5. import com.wsjzzcbq.service.AccountService;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RestController;
    10. /**
    11. * AccountController
    12. *
    13. * @author wsjz
    14. * @date 2023/10/13
    15. */
    16. @RequestMapping("/account")
    17. @RestController
    18. public class AccountController {
    19. @Autowired
    20. private AccountService accountService;
    21. @GetMapping("/find")
    22. public String find() throws JsonProcessingException {
    23. Account account = accountService.list().get(0);
    24. ObjectMapper objectMapper = new ObjectMapper();
    25. String res = objectMapper.writeValueAsString(account);
    26. System.out.println(res);
    27. return res;
    28. }
    29. @RequestMapping("/reduce")
    30. public String debit(String userId, int money) {
    31. try {
    32. accountService.reduce(userId, money);
    33. return "扣款成功";
    34. } catch (Exception e) {
    35. return "扣款失败";
    36. }
    37. }
    38. }

    application.yml 文件

    1. server:
    2. port: 9001
    3. spring:
    4. application:
    5. name: seata-at-account-learn
    6. datasource:
    7. driver-class-name: com.mysql.cj.jdbc.Driver
    8. url: jdbc:mysql://192.168.3.232:3306/pmc-account?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
    9. username: root
    10. password: 123456
    11. cloud:
    12. nacos:
    13. username: nacos
    14. password: nacos
    15. server-addr: 192.168.2.140
    16. discovery:
    17. namespace: public
    18. # server-addr: 192.168.2.140
    19. # config:
    20. # server-addr:
    21. seata:
    22. config:
    23. type: nacos
    24. nacos:
    25. server-addr: ${spring.cloud.nacos.server-addr}
    26. username: ${spring.cloud.nacos.username}
    27. password: ${spring.cloud.nacos.password}
    28. group: SEATA_GROUP
    29. data-id: seata.properties
    30. registry:
    31. type: nacos
    32. nacos:
    33. application: seata-server
    34. cluster: default
    35. server-addr: ${spring.cloud.nacos.server-addr}
    36. username: ${spring.cloud.nacos.username}
    37. password: ${spring.cloud.nacos.password}
    38. group: SEATA_GROUP
    39. # 事物分组,如果不配置默认是spring.application.name + '-seata-service-group'
    40. # tx-service-group:
    41. logging:
    42. level:
    43. com.wsjzzcbq.mapper: debug
    44. mybatis-plus:
    45. global-config:
    46. db-config:
    47. id-type: auto

    关键配置说明

    nacos 注册中心和配置中心默认从 spring.cloud.nacos.server-addr 中获取,因此可以配置一个

    seata config 和 registry,config是客户端在nacos config 中存放的配置文件,它的 group 是 SEATA_GROUP,data-id 是 seata.properties,当然 group 和 data-id 名称是任意自定义的,但要保证和 nacos 中的对应上,否则找不到配置,seata.properties 具体配置内容后面详细说明;registry 配置的是nacos 中seata server 的信息,seata 客户端通过nacos 注册中心中配置的 seata server 的信息获取 seata server 实例,进行连接,这里笔者配置的 seata server group 是 SEATA_GROUP,seata server 的服务名是 seata-server,其实,可以把 seata server 理解为注册在nacos中的服务,相同的服务名,多个实例。项目启动后,会在nacos 注册中心中寻找服务名为 seata-server 的 seata 服务器,seata config、registry、nacos 和 seata server 的关系,看下图

    tx-service-group 事物分组,在同一分布式事物中的服务,需要使用同一事物分组,事物分组如果不配置,默认是 spring.application.name + '-seata-service-group',这里笔者没有配置,使用默认的,即为 seata-at-account-learn-seata-service-group。事物分组是 seata的资源逻辑,事物分组详细说明,看官网文档截图

    1.3、创建 order 服务

    创建子工程 seata-at-order-learn 项目

    seata-at-order-learn pom 文件

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>cloud-learnartifactId>
    7. <groupId>com.wsjzzcbqgroupId>
    8. <version>1.0-SNAPSHOTversion>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>seata-at-order-learnartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>org.springframework.bootgroupId>
    15. <artifactId>spring-boot-starter-webartifactId>
    16. dependency>
    17. <dependency>
    18. <groupId>com.alibaba.cloudgroupId>
    19. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>com.alibaba.cloudgroupId>
    23. <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    24. dependency>
    25. <dependency>
    26. <groupId>org.springframework.cloudgroupId>
    27. <artifactId>spring-cloud-starter-openfeignartifactId>
    28. dependency>
    29. <dependency>
    30. <groupId>org.springframework.cloudgroupId>
    31. <artifactId>spring-cloud-starter-loadbalancerartifactId>
    32. dependency>
    33. <dependency>
    34. <groupId>com.alibaba.cloudgroupId>
    35. <artifactId>spring-cloud-starter-alibaba-seataartifactId>
    36. dependency>
    37. <dependency>
    38. <groupId>com.alibabagroupId>
    39. <artifactId>druid-spring-boot-starterartifactId>
    40. <version>${druid.version}version>
    41. dependency>
    42. <dependency>
    43. <groupId>mysqlgroupId>
    44. <artifactId>mysql-connector-javaartifactId>
    45. <version>${mysql.version}version>
    46. dependency>
    47. <dependency>
    48. <groupId>com.baomidougroupId>
    49. <artifactId>mybatis-plus-boot-starterartifactId>
    50. <version>${mybatis-plus.version}version>
    51. dependency>
    52. dependencies>
    53. <build>
    54. <plugins>
    55. <plugin>
    56. <groupId>org.springframework.bootgroupId>
    57. <artifactId>spring-boot-maven-pluginartifactId>
    58. plugin>
    59. plugins>
    60. build>
    61. project>

    启动类 SeataATOrderApplication

    1. package com.wsjzzcbq;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. import org.springframework.cloud.openfeign.EnableFeignClients;
    6. /**
    7. * SeataATOrderApplication
    8. *
    9. * @author wsjz
    10. * @date 2023/10/14
    11. */
    12. @MapperScan(value = {"com.wsjzzcbq.mapper"})
    13. @EnableFeignClients
    14. @SpringBootApplication
    15. public class SeataATOrderApplication {
    16. public static void main(String[] args) {
    17. SpringApplication.run(SeataATOrderApplication.class, args);
    18. }
    19. }

    订单实体类 Order

    1. package com.wsjzzcbq.bean;
    2. import com.baomidou.mybatisplus.annotation.TableName;
    3. import lombok.Data;
    4. /**
    5. * Order
    6. *
    7. * @author wsjz
    8. * @date 2022/07/07
    9. */
    10. @TableName("order_tbl")
    11. @Data
    12. public class Order {
    13. private Integer id;
    14. private String userId;
    15. private String code;
    16. private Integer count;
    17. private Integer money;
    18. }

    OrderMapper

    1. package com.wsjzzcbq.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.wsjzzcbq.bean.Order;
    4. /**
    5. * OrderMapper
    6. *
    7. * @author wsjz
    8. * @date 2022/07/07
    9. */
    10. public interface OrderMapper extends BaseMapper {
    11. }

    AccountFeign

    1. package com.wsjzzcbq.feign;
    2. import org.springframework.cloud.openfeign.FeignClient;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. import org.springframework.web.bind.annotation.RequestParam;
    5. /**
    6. * AccountFeign
    7. *
    8. * @author wsjz
    9. * @date 2023/10/13
    10. */
    11. @FeignClient(value = "seata-at-account-learn")
    12. public interface AccountFeign {
    13. @RequestMapping("/account/reduce")
    14. String debit(@RequestParam("userId") String userId, @RequestParam("money") int money);
    15. }

    OrderService

    1. package com.wsjzzcbq.service;
    2. import com.baomidou.mybatisplus.extension.service.IService;
    3. import com.wsjzzcbq.bean.Order;
    4. /**
    5. * OrderService
    6. *
    7. * @author wsjz
    8. * @date 2022/07/07
    9. */
    10. public interface OrderService extends IService {
    11. void create(String userId, int money, boolean rollback);
    12. }

    OrderServiceImpl

    1. package com.wsjzzcbq.service.impl;
    2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    3. import com.wsjzzcbq.bean.Order;
    4. import com.wsjzzcbq.feign.AccountFeign;
    5. import com.wsjzzcbq.mapper.OrderMapper;
    6. import com.wsjzzcbq.service.OrderService;
    7. import io.seata.core.context.RootContext;
    8. import io.seata.spring.annotation.GlobalTransactional;
    9. import org.springframework.beans.factory.annotation.Autowired;
    10. import org.springframework.stereotype.Service;
    11. import java.util.UUID;
    12. /**
    13. * OrderServiceImpl
    14. *
    15. * @author wsjz
    16. * @date 2022/07/07
    17. */
    18. @Service
    19. public class OrderServiceImpl extends ServiceImpl implements OrderService {
    20. @Autowired
    21. private AccountFeign accountFeign;
    22. @GlobalTransactional
    23. @Override
    24. public void create(String userId, int money, boolean rollback) {
    25. String xid = RootContext.getXID();
    26. System.out.println(xid);
    27. String orderCode = UUID.randomUUID().toString();
    28. Order order = new Order();
    29. order.setCode(orderCode);
    30. order.setCount(1);
    31. order.setUserId(userId);
    32. order.setMoney(money);
    33. this.save(order);
    34. accountFeign.debit(userId, money);
    35. if (rollback) {
    36. int a = 1/0;
    37. }
    38. }
    39. }

    OrderController

    1. package com.wsjzzcbq.controller;
    2. import com.wsjzzcbq.service.OrderService;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.web.bind.annotation.RequestMapping;
    5. import org.springframework.web.bind.annotation.RestController;
    6. /**
    7. * OrderController
    8. *
    9. * @author wsjz
    10. * @date 2022/07/09
    11. */
    12. @RequestMapping("/order")
    13. @RestController
    14. public class OrderController {
    15. @Autowired
    16. private OrderService orderService;
    17. /**
    18. * http://localhost:9002/order/create?userId=101&money=10&rollback=false
    19. * @param userId
    20. * @param money
    21. * @param rollback
    22. * @return
    23. */
    24. @RequestMapping("/create")
    25. public String create(String userId, int money, boolean rollback) {
    26. try {
    27. orderService.create(userId, money, rollback);
    28. return "下单成功";
    29. } catch (Exception e) {
    30. e.printStackTrace();
    31. return "下单失败";
    32. }
    33. }
    34. }

    application.yml 文件

    1. server:
    2. port: 9002
    3. spring:
    4. application:
    5. name: seata-at-order-learn
    6. datasource:
    7. driver-class-name: com.mysql.cj.jdbc.Driver
    8. url: jdbc:mysql://192.168.3.232:3306/pmc-order?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
    9. username: root
    10. password: 123456
    11. cloud:
    12. nacos:
    13. username: nacos
    14. password: nacos
    15. server-addr: 192.168.2.140
    16. discovery:
    17. namespace: public
    18. # server-addr: 192.168.2.140
    19. # config:
    20. # server-addr:
    21. seata:
    22. config:
    23. type: nacos
    24. nacos:
    25. server-addr: ${spring.cloud.nacos.server-addr}
    26. username: ${spring.cloud.nacos.username}
    27. password: ${spring.cloud.nacos.password}
    28. group: SEATA_GROUP
    29. data-id: seata.properties
    30. registry:
    31. type: nacos
    32. nacos:
    33. application: seata-server
    34. cluster: default
    35. server-addr: ${spring.cloud.nacos.server-addr}
    36. username: ${spring.cloud.nacos.username}
    37. password: ${spring.cloud.nacos.password}
    38. group: SEATA_GROUP
    39. # 事物分组,如果不配置默认是spring.application.name + '-seata-service-group'
    40. tx-service-group: seata-at-account-learn-seata-service-group
    41. logging:
    42. level:
    43. com.wsjzzcbq.mapper: debug
    44. mybatis-plus:
    45. global-config:
    46. db-config:
    47. id-type: auto

    配置说明

    基本和 account 服务配置相同,这里事物分组和 account 服务是一样的 seata-at-account-learn-seata-service-group

    2、添加配置

    2.1、客户端配置

    需要在nacos 中新建 group 是 SEATA_GROUP,data-id 是 seata.properties 的客户端配置

    配置内容如何获取?可以在github 上克隆seata 代码,在源代码 script 目录下有 config-center 目录,在 config-center 目录下有全部配置在 config.txt 文件中

    seata 源代码地址:https://github.com/seata/seata

    另一种方式是下载seata server,笔者下载的 seata server 1.7.1解压后,有 script目录,script目录下config-center 下config.txt 文件中有全部配置

    seata server 下载地址:https://github.com/seata/seata/releases

    config.txt 文件中有英文注释,说明了哪些配置是客户端的哪些是服务端的

    这里笔者已经整理好了客户端配置,在nacos上新建 group 是 SEATA_GROUP,data-id 是 seata.properties 的配置,内容如下

    seata.properties 内容

    1. #For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
    2. #Transport configuration, for client and server
    3. transport.type=TCP
    4. transport.server=NIO
    5. transport.heartbeat=true
    6. transport.enableTmClientBatchSendRequest=false
    7. transport.enableRmClientBatchSendRequest=true
    8. transport.enableTcServerBatchSendResponse=false
    9. transport.rpcRmRequestTimeout=30000
    10. transport.rpcTmRequestTimeout=30000
    11. transport.rpcTcRequestTimeout=30000
    12. transport.threadFactory.bossThreadPrefix=NettyBoss
    13. transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
    14. transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
    15. transport.threadFactory.shareBossWorker=false
    16. transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
    17. transport.threadFactory.clientSelectorThreadSize=1
    18. transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
    19. transport.threadFactory.bossThreadSize=1
    20. transport.threadFactory.workerThreadSize=default
    21. transport.shutdown.wait=3
    22. transport.serialization=seata
    23. transport.compressor=none
    24. #Transaction routing rules configuration, only for the client
    25. service.vgroupMapping.seata-at-account-learn-seata-service-group=default
    26. #If you use a registry, you can ignore it
    27. service.default.grouplist=127.0.0.1:8091
    28. service.enableDegrade=false
    29. service.disableGlobalTransaction=false
    30. #Transaction rule configuration, only for the client
    31. client.rm.asyncCommitBufferLimit=10000
    32. client.rm.lock.retryInterval=10
    33. client.rm.lock.retryTimes=30
    34. client.rm.lock.retryPolicyBranchRollbackOnConflict=true
    35. client.rm.reportRetryCount=5
    36. client.rm.tableMetaCheckEnable=true
    37. client.rm.tableMetaCheckerInterval=60000
    38. client.rm.sqlParserType=druid
    39. client.rm.reportSuccessEnable=false
    40. client.rm.sagaBranchRegisterEnable=false
    41. client.rm.sagaJsonParser=fastjson
    42. client.rm.tccActionInterceptorOrder=-2147482648
    43. client.tm.commitRetryCount=5
    44. client.tm.rollbackRetryCount=5
    45. client.tm.defaultGlobalTransactionTimeout=60000
    46. client.tm.degradeCheck=false
    47. client.tm.degradeCheckAllowTimes=10
    48. client.tm.degradeCheckPeriod=2000
    49. client.tm.interceptorOrder=-2147482648
    50. client.undo.dataValidation=true
    51. client.undo.logSerialization=jackson
    52. client.undo.onlyCareUpdateColumns=true
    53. server.undo.logSaveDays=7
    54. server.undo.logDeletePeriod=86400000
    55. client.undo.logTable=undo_log
    56. client.undo.compress.enable=true
    57. client.undo.compress.type=zip
    58. client.undo.compress.threshold=64k
    59. #For TCC transaction mode
    60. tcc.fence.logTableName=tcc_fence_log
    61. tcc.fence.cleanPeriod=1h
    62. # You can choose from the following options: fastjson, jackson, gson
    63. tcc.contextJsonParserType=fastjson
    64. #Log rule configuration, for client and server
    65. log.exceptionRate=100

    这里需要改的有2处,一个是 service.vgroupMapping.seata-at-account-learn-seata-service-group=default,需要把 service.vgroupMapping. 后面的改成 account项目和 order 项目共同的事物分组 seata-at-account-learn-seata-service-group,这里笔者已经改完,默认的配置不是这个;另一处配置是 service.default.grouplist=127.0.0.1:8091,这里配置的是 seata server 的地址,因为笔者的 seata server 和项目在同一台电脑上,因此不做修改,使用127.0.0.1,读者可根据自己的情况配置

    2.2、服务端配置

    先下载 seata-server-1.7.1,然后进入 seata-server-1.7.1 的 conf 目录

    在 application.yml 文件中进行配置

    spring.application.name 默认是 seata-server ,和前面项目中配置的一样,不用修改

    控制台账号密码默认都是 seata

    seata config 和 registry 是关键,道理和客户端类似,seata server 从nacos 配置中心中获取group 是 SEATA_GROUP,data-id 是 seataServer.properties 的配置

    同时会把自身以group 是 SEATA_GROUP,服务名是 seata-server 的形式注册到 nacos 注册中心

    cluster 是 default,前面客户端的 service.vgroupMapping.seata-at-account-learn-seata-service-group=default,service.default.grouplist=127.0.0.1:8091,都是以 default 对应的

    笔者的 seata-server-1.7.1 的 application.yml  配置内容

    1. # Copyright 1999-2019 Seata.io Group.
    2. #
    3. # Licensed under the Apache License, Version 2.0 (the "License");
    4. # you may not use this file except in compliance with the License.
    5. # You may obtain a copy of the License at
    6. #
    7. # http://www.apache.org/licenses/LICENSE-2.0
    8. #
    9. # Unless required by applicable law or agreed to in writing, software
    10. # distributed under the License is distributed on an "AS IS" BASIS,
    11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12. # See the License for the specific language governing permissions and
    13. # limitations under the License.
    14. server:
    15. port: 7091
    16. spring:
    17. application:
    18. name: seata-server
    19. logging:
    20. config: classpath:logback-spring.xml
    21. file:
    22. path: ${log.home:${user.home}/logs/seata}
    23. extend:
    24. logstash-appender:
    25. destination: 127.0.0.1:4560
    26. kafka-appender:
    27. bootstrap-servers: 127.0.0.1:9092
    28. topic: logback_to_logstash
    29. console:
    30. user:
    31. username: seata
    32. password: seata
    33. seata:
    34. config:
    35. # support: nacos, consul, apollo, zk, etcd3
    36. type: nacos
    37. nacos:
    38. server-addr: 192.168.2.140:8848
    39. namespace:
    40. group: SEATA_GROUP
    41. username: nacos
    42. password: nacos
    43. context-path:
    44. ##if use MSE Nacos with auth, mutex with username/password attribute
    45. #access-key:
    46. #secret-key:
    47. data-id: seataServer.properties
    48. registry:
    49. # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    50. type: nacos
    51. nacos:
    52. application: seata-server
    53. server-addr: 192.168.2.140:8848
    54. group: SEATA_GROUP
    55. namespace:
    56. cluster: default
    57. username: nacos
    58. password: nacos
    59. context-path:
    60. ##if use MSE Nacos with auth, mutex with username/password attribute
    61. #access-key:
    62. #secret-key:
    63. #store:
    64. # support: file 、 db 、 redis
    65. #mode: file
    66. # server:
    67. # service-port: 8091 #If not configured, the default is '${server.port} + 1000'
    68. security:
    69. secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    70. tokenValidityInMilliseconds: 1800000
    71. ignore:
    72. urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

    配置完 seata-server-1.7.1 的 application.yml 文件后

    在nacos 中新建配置 seataServer.properties 

    seataServer.properties 内容

    1. #Transport configuration, for client and server
    2. transport.type=TCP
    3. transport.server=NIO
    4. transport.heartbeat=true
    5. transport.enableTmClientBatchSendRequest=false
    6. transport.enableRmClientBatchSendRequest=true
    7. transport.enableTcServerBatchSendResponse=false
    8. transport.rpcRmRequestTimeout=30000
    9. transport.rpcTmRequestTimeout=30000
    10. transport.rpcTcRequestTimeout=30000
    11. transport.threadFactory.bossThreadPrefix=NettyBoss
    12. transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
    13. transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
    14. transport.threadFactory.shareBossWorker=false
    15. transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
    16. transport.threadFactory.clientSelectorThreadSize=1
    17. transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
    18. transport.threadFactory.bossThreadSize=1
    19. transport.threadFactory.workerThreadSize=default
    20. transport.shutdown.wait=3
    21. transport.serialization=seata
    22. transport.compressor=none
    23. #Log rule configuration, for client and server
    24. log.exceptionRate=100
    25. #Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
    26. store.mode=db
    27. store.lock.mode=db
    28. store.session.mode=db
    29. #Used for password encryption
    30. store.publicKey=
    31. #If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
    32. store.file.dir=file_store/data
    33. store.file.maxBranchSessionSize=16384
    34. store.file.maxGlobalSessionSize=512
    35. store.file.fileWriteBufferCacheSize=16384
    36. store.file.flushDiskMode=async
    37. store.file.sessionReloadReadSize=100
    38. #These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
    39. store.db.datasource=druid
    40. store.db.dbType=mysql
    41. store.db.driverClassName=com.mysql.cj.jdbc.Driver
    42. store.db.url=jdbc:mysql://192.168.3.232:3306/seata?useUnicode=true&rewriteBatchedStatements=true
    43. store.db.user=root
    44. store.db.password=123456
    45. store.db.minConn=5
    46. store.db.maxConn=30
    47. store.db.globalTable=global_table
    48. store.db.branchTable=branch_table
    49. store.db.distributedLockTable=distributed_lock
    50. store.db.queryLimit=100
    51. store.db.lockTable=lock_table
    52. store.db.maxWait=5000
    53. #These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
    54. store.redis.mode=single
    55. store.redis.type=pipeline
    56. store.redis.single.host=127.0.0.1
    57. store.redis.single.port=6379
    58. store.redis.sentinel.masterName=
    59. store.redis.sentinel.sentinelHosts=
    60. store.redis.maxConn=10
    61. store.redis.minConn=1
    62. store.redis.maxTotal=100
    63. store.redis.database=0
    64. store.redis.password=
    65. store.redis.queryLimit=100
    66. #Transaction rule configuration, only for the server
    67. server.recovery.committingRetryPeriod=1000
    68. server.recovery.asynCommittingRetryPeriod=1000
    69. server.recovery.rollbackingRetryPeriod=1000
    70. server.recovery.timeoutRetryPeriod=1000
    71. server.maxCommitRetryTimeout=-1
    72. server.maxRollbackRetryTimeout=-1
    73. server.rollbackRetryTimeoutUnlockEnable=false
    74. server.distributedLockExpireTime=10000
    75. server.xaerNotaRetryTimeout=60000
    76. server.session.branchAsyncQueueSize=5000
    77. server.session.enableBranchAsyncRemove=false
    78. server.enableParallelRequestHandle=true
    79. server.enableParallelHandleBranch=false
    80. #Metrics configuration, only for the server
    81. metrics.enabled=false
    82. metrics.registryType=compact
    83. metrics.exporterList=prometheus
    84. metrics.exporterPrometheusPort=9898

    这里的关键配置是存储 store,默认是 file 文件的形式

    笔者使用 mysql 数据库 db的形式储存事物相关信息

    需修改下面7项内容

    store.mode=db
    store.lock.mode=db
    store.session.mode=db
    store.db.driverClassName=com.mysql.cj.jdbc.Driver
    store.db.url=jdbc:mysql://192.168.3.232:3306/seata?useUnicode=true&rewriteBatchedStatements=true
    store.db.user=root
    store.db.password=123456

    笔者使用 mysql8,因此使用 com.mysql.cj.jdbc.Driver,数据库信息读者根据自己的情况修改

    nacos 中新建 seataServer.properties 

    3、数据库建表

    3.1、seata 服务端建表

    笔者所有数据库使用同一数据库服务器

    新建数据库 seata

    建表 sql 在 seata-server-1.7.1 的 seata-server-1.7.1\seata\script\server\db 目录下

    创建完成,有4张表

    3.2、seata 客户端建表

    seata 为实现分布式事物,业务库下需要有张记录日志的 undo_log 表

    undo_log 表 sql 可以在seata源码 seata\script\client\at\db 目录下找到,不同版本 seata server 会有差异

    笔者 account 服务建表,已包含 undo_log 表

    1. DROP TABLE IF EXISTS `account`;
    2. CREATE TABLE `account` (
    3. `id` int(0) NOT NULL AUTO_INCREMENT,
    4. `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
    5. `money` int(0) NULL DEFAULT 0,
    6. PRIMARY KEY (`id`) USING BTREE
    7. ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    8. -- ----------------------------
    9. -- Records of account
    10. -- ----------------------------
    11. INSERT INTO `account` VALUES (1, '101', 900);
    12. -- ----------------------------
    13. -- Table structure for undo_log
    14. -- ----------------------------
    15. DROP TABLE IF EXISTS `undo_log`;
    16. CREATE TABLE `undo_log` (
    17. `id` bigint(0) NOT NULL AUTO_INCREMENT,
    18. `branch_id` bigint(0) NOT NULL,
    19. `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    20. `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    21. `rollback_info` longblob NOT NULL,
    22. `log_status` int(0) NOT NULL,
    23. `log_created` datetime(0) NOT NULL,
    24. `log_modified` datetime(0) NOT NULL,
    25. PRIMARY KEY (`id`) USING BTREE,
    26. UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    27. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

    笔者 order 服务建表,已包含 undo_log 表

    1. DROP TABLE IF EXISTS `order_tbl`;
    2. CREATE TABLE `order_tbl` (
    3. `id` int(0) NOT NULL AUTO_INCREMENT,
    4. `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
    5. `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
    6. `count` int(0) NULL DEFAULT 0,
    7. `money` int(0) NULL DEFAULT 0,
    8. PRIMARY KEY (`id`) USING BTREE
    9. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    10. -- ----------------------------
    11. -- Table structure for undo_log
    12. -- ----------------------------
    13. DROP TABLE IF EXISTS `undo_log`;
    14. CREATE TABLE `undo_log` (
    15. `id` bigint(0) NOT NULL AUTO_INCREMENT,
    16. `branch_id` bigint(0) NOT NULL,
    17. `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    18. `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    19. `rollback_info` longblob NOT NULL,
    20. `log_status` int(0) NOT NULL,
    21. `log_created` datetime(0) NOT NULL,
    22. `log_modified` datetime(0) NOT NULL,
    23. PRIMARY KEY (`id`) USING BTREE,
    24. UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    25. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

    建表完成

    4、运行测试

    启动 seata-server-1.7.1

    进入 bin 目录,双击 seata-server.bat

    seata 控制台:http://localhost:7091/

    账号密码都是 seata

    启动 account 和 order 服务

    nacos 服务和配置

    测试正常情况

    浏览器请求:http://localhost:9002/order/create?userId=101&money=10&rollback=false

    扣减账户 10 元,新增订单

    测试回滚情况

    5、Seata Server 1.4.2

    seata-server-1.4.2 配置说明

    进入 seata-server-1.4.2 的 conf 目录

    配置文件是 registry.conf 和 file.conf,这个是seata 服务端早期的配置方式,没有1.7.1的application.yml 文件方便

    registry.conf 文件中 registry, 通过 type 指定注册中心,默认是 file,如果使用 nacos,要在下面nacos 配置的位置配置nacos的信息,其他注册中心同理

    registry.conf 文件中 config,通过 type 指定,默认是file,如果使用nacos,需要在下面nacos配置位置配置nacos信息,其他配置中心同理

    file.conf 配置说明(如果registry.conf 文件中 config使用 file,file.conf 配置才生效),通过mode 指定存储形式,默认是file,如果想使用db,需要在下面db配置处配置数据库信息

    6、项目代码

    码云地址:https://gitee.com/wsjzzcbq/csdn-blog/tree/master/cloud-learn

    至此完

  • 相关阅读:
    JavaScript学习笔记——BOM
    2022谷粒商城学习笔记(二)人人开源逆向工程
    【KafkaStream】流式计算概述&KafkaStream入门
    第一章 计算机网络基础
    Git使用总结
    零基础5分钟上手亚马逊云科技AWS核心云架构知识 - 为应用配置自动扩展
    【无标题】
    loadrunner lr解决参数化一次取多条记录【一对多问题】
    SELinux零知识学习十八、SELinux策略语言之类型强制(3)
    vscode c++食用指南
  • 原文地址:https://blog.csdn.net/wsjzzcbq/article/details/133828606