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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM