springcloud + eureka + seata分布式事物

springcloud + eureka + seata分布式事物

1. 前言

​ Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式。

2. 术语

  • TC (Transaction Coordinator) - 事务协调者

    维护全局和分支事务的状态,驱动全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器

    定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器

    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

说明:TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

3. server端

3-1. 下载安装包

​ 下载地址:https://github.com/seata/seata/releases

注意:取最新分支安装包

3-2. 事物日志

​ store mode: filedb

file模式配置项:默认

db模式配置项

  • 初始化数据库信息:https://github.com/seata/seata/blob/1.2.0/script/server/db/mysql.sql(最新分支)
  • 数据库地址及数据库名称
  • 用户名/密码

说明:高可用部署方案需要使用DB模式共享全局事务会话信息。

3-3. 注册中心

​ 注册中心:file 、nacos 、eureka、redis、zk、consul、etcd3、sofa

eg:
eureka {
    serviceUrl = "http://用户名:密码@IP:port/eureka" # 注册中心地址
    application = "idaas-seata-server" # 注册应用名称
    weight = "1" # 权重
  }

说明:高可用部署方案需要注册中心使用非file的seata支持的第三方注册中心。

3-4. 配置中心

​ 配置中心:file、nacos 、apollo、zk、consul、etcd3

eg:
zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }

3-5. 启动

  1. 完成好上述配置

  2. 启动

    Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
      Options:
        --host, -h
          The host to bind.
          Default: 0.0.0.0
        --port, -p
          The port to listen.
       Default: 8091
        --storeMode, -m
       log store mode : file、db
          Default: file
        --help
    
    e.g.
    
    sh seata-server.sh -p 8091 -h 127.0.0.1 -m db &
    

    注意:如果linux启动服务后需要设置在后台运行,堆内存建议分配2G,堆外内存1GE

4. client端

​ 客户端选择springcloud微服务框架

4-1. 依赖

​ 引入依赖:

<!-- spring-cloud-alibaba-seata -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-seata</artifactId>
            <version>${spring-cloud-alibaba-seata.version}</version>
            <!-- 如果内嵌最新版本starter,我们不用排除再引入 -->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 最新版本seata-spring-boot-starter -->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>${seata.version}</version>
        </dependency>

4-2. 创建 UNDO_LOG 表

​ AT 模式需要 UNDO_LOG 表

-- 注意此处0.3.0+ 增加唯一索引 ux_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;

说明:表名可自定义

4-3. 添加seata 配置

​ 使用yml风格,下为基础配置,如需更多配置请查询官网

# -----------seata常用配置,如需修改请参考使用文档--------------
seata:
  enabled: true
  application-id: ${spring.application.name} #服务名
  tx-service-group: default # default是自定义的事务分组名称
  enable-auto-data-source-proxy: true # 启用自动数据源代理
  use-jdk-proxy: false
  service:
    vgroup-mapping:
      default: idaas-seata-server # default是自定义的事务分组名称,idaas-seata-server是tc注册到注册中心的服务名称
    enable-degrade: false # 是否启用降级
    disable-global-transaction: false # 是否禁用全局事务
  config:
    type: file # 配置中心(consul、apollo、etcd3、nacos、zk、file)
  registry:
    type: eureka # 注册中心(consul、etcd3、eureka、nacos、redis、sofa、zk)
    eureka:
      weight: 1
      service-url: ${eureka.client.service-url.defaultZone} # 注册中心地址
  client:
    undo:
      log-table: idaas_seata_undo_log # 自定义undo_log表名

说明:enable-auto-data-source-proxy 可能会与mybatis-plus冲突,如果冲突不能删除undolog,则设置enable-auto-data-source-proxy为false

4-4. 配置数据源

@Configuration
public class DataSourceProxyConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new DruidDataSource();
    }

    @Bean
    public DataSourceProxy dataSourceProxy(DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSourceProxy);
        return sqlSessionFactoryBean.getObject();
    }
}

Hikari 数据源更改DataSource

@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource dataSource() {
    return new HikariDataSource();
}

4-5. 开启事务

  1. 事物起点使用注解:@GlobalTransactional(rollbackFor = Exception.class)

  2. 微服务事物正常使用注解:@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)

    在业务的发起方的方法上使用@GlobalTransactional开启全局事务,Seata 会将事务的 xid 通过拦截器添加到调用其他服务的请求中,实现分布式事务

4-6. 多数据源下使用seata

@Configuration
public class DataSourceProxyConfig {

    @Bean("originOrder")
    @ConfigurationProperties(prefix = "spring.datasource.order")
    public DataSource dataSourceMaster() {
        return new DruidDataSource();
    }

    @Bean("originStorage")
    @ConfigurationProperties(prefix = "spring.datasource.storage")
    public DataSource dataSourceStorage() {
        return new DruidDataSource();
    }

    @Bean("originPay")
    @ConfigurationProperties(prefix = "spring.datasource.pay")
    public DataSource dataSourcePay() {
        return new DruidDataSource();
    }

    @Bean(name = "order")
    public DataSourceProxy masterDataSourceProxy(@Qualifier("originOrder") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean(name = "storage")
    public DataSourceProxy storageDataSourceProxy(@Qualifier("originStorage") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean(name = "pay")
    public DataSourceProxy payDataSourceProxy(@Qualifier("originPay") DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource(@Qualifier("order") DataSource dataSourceOrder,
                                        @Qualifier("storage") DataSource dataSourceStorage,
                                        @Qualifier("pay") DataSource dataSourcePay) {

        DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();

        Map<Object, Object> dataSourceMap = new HashMap<>(3);
        dataSourceMap.put(DataSourceKey.ORDER.name(), dataSourceOrder);
        dataSourceMap.put(DataSourceKey.STORAGE.name(), dataSourceStorage);
        dataSourceMap.put(DataSourceKey.PAY.name(), dataSourcePay);

        dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceOrder);
        dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);

        DynamicDataSourceContextHolder.getDataSourceKeys().addAll(dataSourceMap.keySet());

        return dynamicRoutingDataSource;
    }

    @Bean
    @ConfigurationProperties(prefix = "mybatis")
    public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DataSource dataSource) {
        // 这里用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(dataSource);
        return mybatisSqlSessionFactoryBean;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值