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

原文地址:https://www.cnblogs.com/wwjj4811/p/13640693.html