• Spring Cloud Alibaba:Seata基础知识


    介绍

    Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
    分布式事务处理过程一ID+三组件模型:
    Transaction ID XID 全局唯一的事务ID
    三组件:
    TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
    TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
    RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
    Seata处理过程:

    1.TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID.
    2.XID在微服务调用链路的上下文中传播。
    3.RM向TC注册分支事务,将其纳入XID对应全局事务的管辖。
    4.TM向TC发起针对XID的全局提交或回滚决议。
    5.TC调度XID下管辖的全部分支事务完成提交或回滚请求。

    安装

    从github上下载seata-server09的zip包,解压之后,进入conf目录,修改配置文件file.conf

    然后在本机创建seata数据库,并执行conf目录下的db_store.sql文件
    修改register.conf配置文件,修改注册中心为nacos,并配置连接地址,双击bin目录下的seata-server.bat.

    建库

    CREATE DATABASE seata_order;
    USE seata_order;
    CREATE TABLE t_order(
        id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
        user_id BIGINT(11) DEFAULT NULL COMMENT '用户id',
        product_id BIGINT(11) DEFAULT NULL COMMENT '产品id',
        count INT(11) DEFAULT NULL COMMENT '数量',
        money DECIMAL(11,0) DEFAULT NULL COMMENT '金额',
        status INT(1) DEFAULT NULL COMMENT '订单状态:0创建中,1已完结'
    )ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
    INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES ('51', '1', '1', '10', '100', '1');
    INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES ('52', '1', '1', '10', '100', '1');
    INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES ('54', '1', '1', '10', '100', '1');
    INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES ('55', '1', '1', '10', '100', '0');
    CREATE DATABASE seata_storage;
    USE seata_storage;
    CREATE TABLE t_storage(
        id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
        product_id BIGINT(11) DEFAULT NULL COMMENT '产品id',
        total INT(11) DEFAULT NULL COMMENT '总库存',
        used INT(11) DEFAULT NULL COMMENT '已用库存',
        residue INT(11) DEFAULT NULL COMMENT '剩余库存'
    )ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
    INSERT INTO t_storage(id, product_id, total, used, residue) VALUES(1,1,100,0,100);
    CREATE DATABASE seata_account;
    USE seata_account;
    CREATE TABLE t_account(
        id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
        user_id BIGINT(11) DEFAULT NULL COMMENT '用户id',
        total DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
        used DECIMAL(10,0) DEFAULT NULL COMMENT '已用额度',
        residue DECIMAL(10,0) DEFAULT 0 COMMENT '剩余可用额度'
    )ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
    INSERT INTO t_account(id, user_id, total, used, residue) VALUES(1,1,1000,0,1000);
    

    建完三个数据库后,分别在三个库中执行conf目录下的db_undo_log.sql回滚表
    总计:

    搭建微服务

    业务需求:下订单->减库存->扣余额->改订单状态
    三个微服务只示范订单微服务:
    pom依赖:

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>io.seata</groupId>
                        <artifactId>seata-all</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-all</artifactId>
                <version>0.9.0</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    

    配置文件:

    server:
      port: 2001
    
    spring:
      application:
        name: seata-order-service
      cloud:
        alibaba:
          seata:
            #事务组的名称,与file.conf中的组名相同
            tx-service-group: wj_group
        nacos:
          discovery:
            server-addr: 192.168.10.137:8848
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/seata_order
        username: root
        password: 1234
    logging:
      level:
        io:
          seata: info
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
    
    

    主启动类:

    @MapperScan("com.wj.springcloud.dao")
    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
    @EnableDiscoveryClient
    @EnableFeignClients
    public class SeataOrderMainApp2001 {
        public static void main(String[] args) {
            SpringApplication.run(SeataOrderMainApp2001.class,args);
        }
    }
    

    配置类:

    @Configuration
    public class DataSourceProxyConfig {
    
        @Value("${mybatis.mapperLocations}")
        private String mapperLocations;
    
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druidDataSource() {
            return new DruidDataSource();
        }
    
        @Bean
        public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
            return new DataSourceProxy(druidDataSource);
        }
    
        @Bean
        public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSourceProxy);
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            bean.setMapperLocations(resolver.getResources(mapperLocations));
            return bean.getObject();
        }
    }
    

    service,controller和mapper以及mapper.xml省略
    使用@GlobalTransactional注解开启分布式事务

    @Service
    @Slf4j
    public class OrderServiceImpl implements OrderService {
    
        @Autowired
        private OrderDao orderDao;
    
        @Autowired
        private AccountService accountService;
    
        @Autowired
        private StorageService storageService;
    
        @Override
        @GlobalTransactional
        public void create(Order order) {
            log.info("---->开始新建订单");
            orderDao.create(order);
            log.info("---->订单微服务开始调用库存,做扣减");
            storageService.decrease(order.getProductId(),order.getCount());
            log.info("---->订单微服务开始调用账户,做扣减");
            accountService.decrease(order.getUserId(),order.getMoney());
            log.info("---->修改订单状态");
            orderDao.update(order.getUserId(),0);
    
            log.info("下订单结束");
        }
    }
    @Component
    @FeignClient(value="seata-account-service")
    public interface AccountService {
    
        @PostMapping("/account/decrease")
        CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("count") BigDecimal count);
    
    }
    
    @Component
    @FeignClient(value="seata-storage-service")
    public interface StorageService {
    
        @PostMapping("/storage/decrease")
        CommonResult decrease(@RequestParam("productId") Long productId,@RequestParam("count") Integer count);
    }
    

    以往所有SpringCloud代码已上传至github:https://github.com/JGZY/cloud2020

  • 相关阅读:
    04747_Java语言程序设计(一)_第9章_输入和输出流
    如何发布自己的服务---zookeeper
    django获取前端有multiple属性的select的多选项
    MYSQL性能优化的最佳20+条经验
    select * from 为什么效率低?
    django无法同步数据库 Error loading MySQLdb module: No module named ‘MySQLdb‘
    SQL的主键和外键和唯一约束
    为什么要把某些数据库表设计成一对一的关系
    Bootstrap 模态框(Modal)插件数据传值
    Django模板遍历字典的方法
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/13640693.html
Copyright © 2020-2023  润新知