seata+nacos 实现 AT 模式分布式事务

问尤龙の时光 该配合你演出的我,却视而不见。。 本文由博客端 http://www.wenyoulong.com 主动推送

1、AT 模式简介

AT 模式官网已经给出了很详细的介绍,可以直接看官网

http://seata.io/zh-cn/docs/dev/mode/at-mode.html

2、建立项目

涉及的代码过多,这里只对几个关键的步骤进行说明,完整代码可以到 git 上下载,AT 模式在 master 分支上,数据库脚本在 script 目录下

https://gitee.com/WylLoveX/seata.git

2.1、maven 依赖

这里我们建立一个 spring boot 项目,基于 2.2.5.RELEASE 版本,引入 seata 和 nacos 需要的依赖。

spring-cloud-starter-alibaba-seata 内部封装了 seata 分布式事务的 XID 的传递,引入直接使用,如果不用这个组件,就只能自己解决 XID 传递的问题;

seata-spring-boot-starter 的版本号和 seata 版本保持一致;


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>2.2.5.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
</dependencies>
  

2.2、yml 配置

先配置将服务注册到 nacos,然后对 seata 进行配置,seata 的 tx-service-group 的值,对应了 seata 事务组的配置,例如,我这个服务的 seata.tx-service-group 的值为 order_group,那就要和 seata 中的配置对应

service.vgroupMapping.order_group=default

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://10.116.11.110:3306/order?useUnicode=true&characeterEncoding=utf-8&serverTimezone=UTC&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: order
  cloud:
    nacos:
      discovery:
        server-addr: 10.116.11.110:8848
logging:
  level:
    io:
      seata: debug
mybatis:
  # Mybatis配置Mapper路径
  mapper-locations: classpath:mapper/**/*.xml
seata:
  tx-service-group: order_group
  config:
    type: nacos
    nacos:
      server-addr: 10.116.11.110:8848
      group: SEATA_GROUP

2.3、数据源配置

然后我们需要设置 mybatis 使用 seata 的数据源代理

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.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * @author Mr.Wen
 * @version 1.0
 * @date 2021-10-27 19:06
 */

@Configuration
public class DataSourceProxyConfig {

    @Value("${mybatis.mapper-locations}")
    private String mapperLocations;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDatasource(){
        return new DruidDataSource();
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource datasource) throws Exception{
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(new DataSourceProxy(datasource));
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        return sessionFactoryBean.getObject();
    }

}

2.4、undo_log

AT 模式下,每个服务对应的库中,都要建立 undo_log 表

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

2.5、项目启动

启动需要几个注解,因为我们自己建立了数据源,所以就直接剔除 spring boot 的数据源自动配置

/**
 * @author Mr.Wen
 * @version 1.0
 * @date 2021-10-21 16:59
 */
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@Import(DataSourceProxyConfig.class)
public class OrderApplication {
    public static void main(String[] args){
        SpringApplication.run(OrderApplication.class);
    }
}

3、使用

事务发起端添加全局事务注解 @GlobalTransactional,同时注意不要捕获异常,否则事务不会回滚

事务发起端:

image.png

事务参与:

image.png

image.png

4、注意

这个模式的核心是 undo_log 表,这个表记录的操作的数据在事务提交前的状态和事务提交后的状态,本地事务会将 undo_log 和我们的数据库操作一起提交,所以,我们在 3 中的全局事务发起者中打个断点,会发现事务已经是提交了的,出错回滚的话,其实并不是我们理解的 rollback,因为我们修改数据的事务已经提交了,seata 的回滚就是读取 undo_log 表的操作日志,找到对应数据的事务提交前的记录,将他重新设置为事务提交前的样子。全局事务回滚或者提交后,会删除 undo_log 中对应的记录。

分布式事务如果回滚失败,可以检查下 XID 是否传递成功。

  • 开发
    33 引用 • 156 回帖 • 1 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2991 引用 • 8142 回帖 • 592 关注
  • Nacos
    19 引用 • 4 回帖 • 1 关注
  • seata
    3 引用
1 操作
wenyl 在 2021-11-03 11:45:29 更新了该帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...