• SpringCloud Alibaba学习(四)——seata


    Seata是一款开源的分布式解决方案,提供高性能和简单易用的额分布式事务服务。提供了AT、TCC、SAGA和XA事务模式

    Seata事务管理中三个重要的角色:

    1.TC(Transaction Coordinate)-事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚

    2.TM(Transition Manager)-事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务

    3.RM(Resource Manager)-资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚

     

    Seata提供四种不同的分布式事务解决方案:

    XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入

    TCC模式:最终一致的分阶段事务模式,有业务侵入

    AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式

    SAGA模式:长事务模式,有业务侵入 

     解压Seata,修改registry.conf配置文件

    1.选择自己要使用的配置中心(nacos)全部替换成nacos;

    2.修改file.conf(存储模式)

    Server的存储模式(mode)支持三种:

    1. file:(默认)单击模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高(默认)
    2. db:高可用模式,全局事务会话信息通过db共享,相应性能差些
    3. Redis:Seata-server1.3以及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置合适当前场景的redis持久化配置资源目录

     在数据库中创建数据库seata,,创建数据库表

    1. CREATE TABLE `branch_table` (
    2. `branch_id` bigint NOT NULL,
    3. `xid` varchar(128) NOT NULL,
    4. `transaction_id` bigint DEFAULT NULL,
    5. `resource_group_id` varchar(32) DEFAULT NULL,
    6. `resource_id` varchar(256) DEFAULT NULL,
    7. `branch_type` varchar(8) DEFAULT NULL,
    8. `status` tinyint DEFAULT NULL,
    9. `client_id` varchar(64) DEFAULT NULL,
    10. `application_data` varchar(2000) DEFAULT NULL,
    11. `gmt_create` datetime(6) DEFAULT NULL,
    12. `gmt_modified` datetime(6) DEFAULT NULL,
    13. PRIMARY KEY (`branch_id`),
    14. KEY `idx_xid` (`xid`)
    15. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    16. CREATE TABLE `distributed_lock` (
    17. `lock_key` char(20) NOT NULL,
    18. `lock_value` varchar(20) NOT NULL,
    19. `expire` bigint DEFAULT NULL,
    20. PRIMARY KEY (`lock_key`)
    21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    22. CREATE TABLE `global_table` (
    23. `xid` varchar(128) NOT NULL,
    24. `transaction_id` bigint DEFAULT NULL,
    25. `status` tinyint NOT NULL,
    26. `application_id` varchar(32) DEFAULT NULL,
    27. `transaction_service_group` varchar(32) DEFAULT NULL,
    28. `transaction_name` varchar(128) DEFAULT NULL,
    29. `timeout` int DEFAULT NULL,
    30. `begin_time` bigint DEFAULT NULL,
    31. `application_data` varchar(2000) DEFAULT NULL,
    32. `gmt_create` datetime DEFAULT NULL,
    33. `gmt_modified` datetime DEFAULT NULL,
    34. PRIMARY KEY (`xid`),
    35. KEY `idx_status_gmt_modified` (`status`,`gmt_modified`),
    36. KEY `idx_transaction_id` (`transaction_id`)
    37. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    38. CREATE TABLE `lock_table` (
    39. `row_key` varchar(128) NOT NULL,
    40. `xid` varchar(128) DEFAULT NULL,
    41. `transaction_id` bigint DEFAULT NULL,
    42. `branch_id` bigint NOT NULL,
    43. `resource_id` varchar(256) DEFAULT NULL,
    44. `table_name` varchar(32) DEFAULT NULL,
    45. `pk` varchar(36) DEFAULT NULL,
    46. `status` tinyint NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    47. `gmt_create` datetime DEFAULT NULL,
    48. `gmt_modified` datetime DEFAULT NULL,
    49. PRIMARY KEY (`row_key`),
    50. KEY `idx_status` (`status`),
    51. KEY `idx_branch_id` (`branch_id`),
    52. KEY `idx_xid` (`xid`)
    53. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

     修改script-config-center文件中的config.txt,同样将存储模式改为db,修改具体信息;配置自己分组service.vgroup_mapping.my_test_tx_group=default改为service.vgroup_mapping.自己=default

    将配置文件配置到nacos,使用git

     

     

     即配置成功!

    下面进行模拟分布式事务:分别创建两个数据库(假设)-order订单数据库-money支付表数据库,即对应的订单表和支付表。分别创建两个项目:支付和订单

    模拟之前一定要在两个数据库中加入undo_log表

    1. CREATE TABLE `undo_log` (
    2. `id` bigint NOT NULL AUTO_INCREMENT,
    3. `branch_id` bigint NOT NULL,
    4. `xid` varchar(100) NOT NULL,
    5. `context` varchar(128) NOT NULL,
    6. `rollback_info` longblob NOT NULL,
    7. `log_status` int NOT NULL,
    8. `log_created` datetime NOT NULL,
    9. `log_modified` datetime NOT NULL,
    10. `ext` varchar(100) DEFAULT NULL,
    11. PRIMARY KEY (`id`),
    12. UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
    13. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3

    支付模块

    1. server.port=8803
    2. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    3. spring.datasource.url= jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    4. spring.datasource.username= root
    5. spring.datasource.password= 123456
    6. mybatis.configuration.map-underscore-to-camel-case= true
    7. spring.cloud.nacos.discovery.server-addr=localhost:8848
    8. spring.application.name=money
    9. spring.cloud.alibaba.seata.tx-service-group=guangzhou
    10. #配置seata的注册中心,告诉seata client 怎么去访问seata servellr
    11. seata.registry.type=nacos
    12. #可不配服务名
    13. seata.registry.nacos.application=seata-server
    14. seata.registry.nacos.server-addr= localhost:8848
    15. seata.registry.nacos.username=nacos
    16. seata.registry.nacos.password=nacos
    17. #seata server所在的分组,默认就是这个,没有可以不配
    18. seata.registry.nacos.group=SEATA_GROUP
    19. #配置seata的配置中心,
    20. seata.config.type=nacos
    21. seata.config.nacos.server-addr=localhost:8848
    22. seata.config.nacos.username=nacos
    23. seata.config.nacos.password=nacos
    1. @Mapper
    2. @Repository
    3. public interface MoneyMapper {
    4. public int subMoney();
    5. }
    1. @Service
    2. public class MoneyService {
    3. @Resource
    4. private MoneyMapper moneyMapper;
    5. public void subMoney(){
    6. moneyMapper.subMoney();
    7. }
    8. }
    1. @RestController
    2. public class MoneyController {
    3. @Resource
    4. MoneyService moneyService;
    5. @RequestMapping("/money")
    6. public String money(){
    7. moneyService.subMoney();
    8. return "支付成功";
    9. }
    10. }
    1. "1.0" encoding="UTF-8" ?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="com.example.seatamoney.mapper.MoneyMapper">
    6. <update id="subMoney">
    7. update moneyTest set money=money-10 where id=1;
    8. update>
    9. mapper>

    订单模块

    1. server.port=8180
    2. provider.ribbon.NFLoadBalancerRuleClassName:com.example.consumer.configuration.NacosWeightedRule
    3. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    4. spring.datasource.url= jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    5. spring.datasource.username= root
    6. spring.datasource.password= 123456
    7. mybatis.mapper-locations= classpath:com/example/consumer/mapper/*.xml
    8. mybatis.configuration.map-underscore-to-camel-case= true
    9. spring.cloud.nacos.discovery.server-addr=localhost:8848
    10. spring.application.name=consumer
    11. spring.cloud.alibaba.seata.tx-service-group=guangzhou
    12. #配置seata的注册中心,告诉seata client 怎么去访问seata server
    13. seata.registry.type=nacos
    14. #可不配服务名
    15. seata.registry.nacos.application=seat-server
    16. seata.registry.nacos.server-addr= localhost:8848
    17. seata.registry.nacos.username=nacos
    18. seata.registry.nacos.password=nacos
    19. #seata server所在的分组,默认就是这个,没有可以不配
    20. seata.registry.nacos.group=SEATA_GROUP
    21. #配置seata的配置中心,
    22. seata.config.type=nacos
    23. seata.config.nacos.server-addr=localhost:8848
    24. seata.config.nacos.username=nacos
    25. seata.config.nacos.password=nacos

    openFeign接口

    1. @Component
    2. @FeignClient(value = "money")
    3. public interface MoneyFeign {
    4. @RequestMapping("/money")
    5. public String money();
    6. }
    1. @Repository
    2. @Mapper
    3. public interface OrderMapper {
    4. public int addOrder();
    5. }
    1. "1.0" encoding="UTF-8" ?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="com.example.consumer.mapper.OrderMapper">
    6. <update id="addOrder">
    7. update orders set num=num+1 where id=1;
    8. update>
    9. mapper>
    1. @Service
    2. public class OrderService {
    3. @Resource
    4. private OrderMapper orderMapper;
    5. public void addOrder(){
    6. orderMapper.addOrder();
    7. }
    8. }
    1. @RestController
    2. public class OrderController {
    3. @Resource
    4. OrderService orderService;
    5. @Resource
    6. MoneyFeign moneyFeign;
    7. @RequestMapping("/order")
    8. @GlobalTransactional
    9. public String Order(){
    10. moneyFeign.money();
    11. int i = 1/0;
    12. orderService.addOrder();
    13. return "下单成功";
    14. }
    15. }
    1. @SpringBootApplication
    2. @EnableFeignClients
    3. @MapperScan("com.example.consumer.mapper")
    4. public class ConsumerApplication {
    5. public static void main(String[] args) {
    6. SpringApplication.run(ConsumerApplication.class, args);
    7. }
    8. }

    如果Controller不加@GlobalTransitional注解,最后支付表-10元,但是订单表不变;

    加上分布式事务后,两表都不发生变化

  • 相关阅读:
    Go语言的跨文件调包
    Vuex的基本使用
    网络协议与攻击模拟_17HTTPS 协议
    【kr】强化学习之旅 1 环境配置
    天猫复购预测训练赛技术报告
    优雅使用前端枚举Enum,符合国标的那种!
    线程安全问题(模拟取钱案例)
    【PHP库】phpseclib - sftp远程文件操作
    Spring中@Bean标注的方法是如何创建对象呢?
    自己实现str
  • 原文地址:https://blog.csdn.net/qq_36149079/article/details/127648037