5. Distributed transaction management - Seata

        Since the @Transactional annotation can only control the transaction of the server A where it is located, when the method calls the method of other server B, when the method in A makes an error, @Transactional can only roll back the SQL in the method in A, and A calls B's SQL in method cannot be rolled back

1. Set

        Seata (Distributed Transaction Solution) is an open source distributed transaction solution designed to solve distributed transaction problems in distributed systems.

1.1 Features of Seata

1. Distributed transaction coordination:

        Seata provides a Global Transaction Coordinator (GTC for short) to manage distributed transactions and coordinate the commit or rollback of each branch transaction.

2. Transaction log:

        Seata uses a transaction log to ensure data consistency of distributed transactions. It logs the duration of the transaction operation so that it can be rolled back or compensated if needed.

3. Distributed lock:

        Seata supports distributed locks for coordinating concurrent operations in distributed transactions.

4. Data source agent:

        Seata provides a data source agent to intercept database operations to achieve transaction isolation and management.

5. High availability:

        Seata supports cluster deployment to ensure that it can still work normally when a node fails.

6. Support multiple frameworks:

        Seata supports integration into common Java frameworks and middleware, such as Spring, Spring Boot, Dubbo, etc.

1.2 Seata transaction mode

        AT Mode: See Seata AT Mode document

        TCC mode: see "Seata TCC Mode" document

        Saga mode: see "SEATA Saga Mode" document

1.3 Seata's role composition

        TC  (Transaction Coordinator) - Transaction Coordinator: maintains the state of global and branch transactions, and drives global transaction commit or rollback.

        TM  (Transaction Manager) - Transaction Manager: Define the scope of global transactions , start global transactions, commit or rollback global transactions.

        RM  ( Resource Manager ) - Resource Manager: manages resources ( Resource ) of branch transactions , talks to TC to register branch transactions and report the status of branch transactions, and drives branch transaction commit or rollback.

1.4 Use of Seata 

This article in the download center will introduce you how to click to know the details of each version and upgrade precautions. https://seata.io/zh-cn/blog/download.html

1.4.1 Configuration conf file

        Download a mysql-connector-java-8.0.20.jar in /lib (consistent with your own mysql version)

        /conf/file.conf

96L driver-class-name = "com.mysql.cj.jdbc.Driver" #mysql 8 version to add.cj

98L user = "xxxx" #database account
99L password = "xxxx" #database password

        /conf/registry.conf

  3L type = "eureka" #Access to the registration center

10L        eureka {
11L                serviceUrl = "http://localhost:8761/eureka"
12L                application = "default"
13L                weight = "1"

14L        }

1.4.2 Solve the problem of startup failure of different versions of jdk installed

        seata-server.bat 

71L        if "%JAVACMD%"=="" set JAVACMD="D:\install\JDK\bin\java.exe"

1.4.3 Create a database 

-- seata
DROP DATABASE IF EXISTS seata;
CREATE DATABASE seata DEFAULT CHARACTER SET utf8;
USE seata;
-- 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`)
);
-- the table to store seata xid data  回滚日志表
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;

1.4.4 Create a log table in the project database

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;

 1.4.5 Configuration in projects involving distributed business requirements

        Copy file.conf and registry.conf to the resources package and modify

file.conf

31L        vgroup_mapping.fsp_tx_group = "default"

97L #Change the database to project database instead of seata database

        import dependencies

<!--druid-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.15</version>
</dependency>
<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.1.0.RELEASE</version>
    <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>

        configuration configuration class

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 {
    /*
     * @ConfigurationProperties用于application.yml中的配置信息
     * prefix:前缀定义了读取到application.yml中哪些属性,在创建完对象之后,在加入IOC
     * 容器里面之后会自动给该对象的属性赋值
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
    /*
     * 设置DataSource代理,主要目的是让mybatis在获取datasource时获取到由druid代理的dataSource
     * 能够让seata管理到数据库的操作,实现分布式事务
     * 通过DataSourceProxy能在业务代码的事务提交时,seata通过这个切入点,来给TC发送RM的处理结果
     *
     * 当一个接口有2个不同实现时,使用@Autowired注解时会报
     * org.springframework.beans.factory.NoUniqueBeanDefinitionException异常信息
     * Primary用于高速spring在不知道该注入哪个bean时,优先使用选择该bean
     *
     * DataSourceProxy extends AbstractDataSourceProxy
     * AbstractDataSourceProxy implements javax.sql.DataSource
     *
     */
    @Primary
    @Bean("dataSource")
    public DataSourceProxy dataSource(DataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }

    /*
     * 创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //设置数据源   javax.sql.DataSource
        sqlSessionFactoryBean.setDataSource(dataSourceProxy);
        //加载mapper文件
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:/mapper/*.xml"));
        //设置事务工厂,用于创建事务
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        //创建工厂对象
        return sqlSessionFactoryBean.getObject();
    }
}

        Configured in the main configuration

spring:
  cloud:
    alibaba:
      seata:
        tx-service-group: fsp_tx_group

        The default data source of spring-boot is discarded in the main startup class

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

1.4.6 Replace @Transactional involving distributed business with @GlobalTransactional

1.4.7 start seata

        Start the eureka registration center before starting, and then start the command line in the bin folder

seata-server.bat

1.4.8 io.seata.common.exception.ShouldNeverHappenException: get tablemeta failed

        If this error occurs, add useInformationSchema=false to the database url in the main configuration file

Guess you like

Origin blog.csdn.net/LB_bei/article/details/132405817