Alibaba Seata 分布式事務管理


Alibaba   Seata  分布式事務管理

 

官網: http://seata.io/zh-cn/

 

Seata 是什么?

Seata 是一款開源的分布式事務解決方案,致力於提供高性能和簡單易用的分布式事務服務。

 

Seata有3個基本組成部分:

事務協調器(TC):   維護全局事務和分支事務的狀態,驅動全局提交或回滾。

事務管理器TM:          定義全局事務的范圍:開始全局事務,提交或回滾全局事務。

資源管理器(RM):  管理分支事務處理的資源,與TC交談以注冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾。

 

 

Seata管理的分布式事務的典型生命周期:

1、TM要求TC開始一項新的全局事務。TC生成代表全局事務的XID。

2、XID通過微服務的調用鏈傳播。

3、RM將本地事務注冊為XID到TC的相應全局事務的分支。

4、TM要求TC提交或回退相應的XID全局事務。

5、TC驅動XID的相應全局事務下的所有分支事務以完成分支提交或回滾。

 

 

 Seata下載地址:

https://github.com/seata/seata/tags

解壓后:

 

 

1、如果是1.0之前的版本 打開  conf  文件夾,找到   db_store.sql  mysql腳本文件在mysql中建表,1.1.0解壓后沒有,參考下面的建表語句:

-- the table to store GlobalSession data
drop table if exists `global_table`;
create table `global_table` (
  `xid` varchar(128)  not null,
  `transaction_id` bigint,
  `status` tinyint not null,
  `application_id` varchar(32),
  `transaction_service_group` varchar(32),
  `transaction_name` varchar(128),
  `timeout` int,
  `begin_time` bigint,
  `application_data` varchar(2000),
  `gmt_create` datetime,
  `gmt_modified` datetime,
  primary key (`xid`),
  key `idx_gmt_modified_status` (`gmt_modified`, `status`),
  key `idx_transaction_id` (`transaction_id`)
);

-- the table to store BranchSession data
drop table if exists `branch_table`;
create table `branch_table` (
  `branch_id` bigint not null,
  `xid` varchar(128) not null,
  `transaction_id` bigint ,
  `resource_group_id` varchar(32),
  `resource_id` varchar(256) ,
  `lock_key` varchar(128) ,
  `branch_type` varchar(8) ,
  `status` tinyint,
  `client_id` varchar(64),
  `application_data` varchar(2000),
  `gmt_create` datetime,
  `gmt_modified` datetime,
  primary key (`branch_id`),
  key `idx_xid` (`xid`)
);

-- the table to store lock data
drop table if exists `lock_table`;
create table `lock_table` (
  `row_key` varchar(128) not null,
  `xid` varchar(96),
  `transaction_id` long ,
  `branch_id` long,
  `resource_id` varchar(256) ,
  `table_name` varchar(32) ,
  `pk` varchar(36) ,
  `gmt_create` datetime ,
  `gmt_modified` datetime,
  primary key(`row_key`)
);

各個表對應功能:

  • 全局事務---global_table
  • 分支事務---branch_table
  • 全局鎖-----lock_table

 

2、修改   file.conf  配置文件

 

因為我使用的是mysql8.0, 但是  /seata/lib  目錄下的mysql驅動是

 所以如果你也是mysql8.0,需要刪除這個jar,重新添加:

 

 

3.修改conf文件夾下的 registry.conf,  根據自己的實際情況修改,nacos默認端口號是8848

 

 

使用案例:

以用戶購買商品的業務邏輯為例。整個業務邏輯由3個微服務提供支持:

  • 倉儲服務:對給定的商品扣除倉儲數量。
  • 訂單服務:根據采購需求創建訂單。
  • 帳戶服務:從用戶帳戶中扣除余額。

如果該操作跨越3個不同的數據庫來操作,那么就存在分布式事務的問題。

 

 

 

 

 測試開始:

1: 創建3個數據庫: seata_order(訂單)、 seata_storage(庫存)、seata_account(用戶的賬戶信息)

分別創建對應的表:order、storage、account表

 

2:   每個庫都創建    db_undo_log.sql 里面的表,同樣的Seata1.0之前的版本conf下面有,1.0之后的參考下面:

-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此腳本必須初始化在你當前的業務數據庫中,用於AT 模式XID記錄。與server端無關(注:業務數據庫)
-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
drop table `undo_log`;
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

 

建java服務項目:

1、maven依賴:

<dependencies>
        <!--cloud alibaba nacos- discovery-->
        <dependency>
            <groupId> com.alibaba.cloud </groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata -->
        <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <artifactId>seata-all</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <!--seata-all 與下載的server保持一致 --> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>1.1.0</version> </dependency>

        <!-- openFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
<!-- Druid 數據庫連接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>

 

2、yml:

server:
  port: 2001

spring:
  application:
    name: seata-order-service
  cloud:
    alibaba:
      seata:
       # 自定義的事務組名稱,需要與seata-server 的conf文件里面配置的一致
        tx-service-group: default
    nacos:
      discovery:
        server-addr: localhost:8848
  datasource:
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.2.241:3306/common_dev_scheme?useSSL=false&characterEncoding=utf8&autoReconnect=true
      username: root
      password: 123456
      filters: stat
      # 設置最大數據庫連接數,設為0為無限制
      maxActive: 20
      # 配置初始化大小、最小、最大
      initialSize: 1
      #  最大等待時間
      maxWait: 60000
      # 始終保留在池中的最小連接數,如果連接驗證失敗將縮小至此值
      minIdle: 1
      timeBetweenEvictionRunsMillis: 6000
#      連接在池中保持空閑而不被回收的最小時間(毫秒)
      minEvictableIdleTimeMillis: 30000
      validationQuery: select 'x'
#      對池中空閑的連接是否進行驗證,驗證失敗則回收此連接(默認為false)
      testWhileIdle:  true
#       當從連接池中取出一個連接時是否進行驗證,若驗證失敗則從池中刪除該連接並嘗試取出另一個連接
      testOnBorrow: true
#      當一個連接使用完歸還到連接池時是否進行驗證
      testOnReturn: false
#      啟用游標緩存,這個對數據庫的性能提升很大
      poolPreparedStatements: true
#        要啟用PSCache,必須配置大於0,當大於0時,poolPreparedStatements自動觸發修改為true。在Druid中,不會存在Oracle下PSCache占用內存過多的問題,可以把這個數值配置大一些,比如說100
      maxOpenPreparedStatements: 20
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 2000
mybatis:
  mapper-locations: classpath:mapper/*.xml

 

3、拷貝seata-server包下面的 file.conf 和 registry.conf 到resource目錄下

 

我們需要排除掉SpringBoot默認自動注入的  DataSourceAutoConfigurationBean , 因為SEATA是基於數據源攔截來實現的分布式事務,因此,我們需要自定義數據源配置信息:

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

 

package com.geekplus.broadway.ws.tally.application; import com.alibaba.druid.pool.DruidDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.transaction.SpringManagedTransactionFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration public class DataSourceConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } @Primary @Bean("dataSource") public DataSourceProxy dataSource(DataSource druidDataSource){ return new DataSourceProxy(druidDataSource); } @Bean public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSourceProxy); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath*:/com.dw.study/*.xml")); sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory()); return sqlSessionFactoryBean.getObject(); } }

 

該配置類,一般放在與啟動類相同的目錄即可!

 

 

使用全局事務:

 

 

 

 


免責聲明!

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



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