springCloud整合seata实现分布式事务

seata简介

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

  • 对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入
  • 高性能:减少分布式事务解决方案所带来的性能消耗

seata术语 

        TC (Transaction Coordinator) 事务协调者 :维护全局和分支事务的状态,驱动全局事务提交或回滚。

        TM (Transaction Manager) 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。

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

        关系图:         

image-20210215174627345

        UNDO_LOG表: 

        1. 必须在每个业务数据库中创建,用于保存回滚操作数据;

        2. 当全局提交时,记录删除;

        3. 当全局回滚时,将现有数据撤销。还原至操作前的状态(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;

AT模式详解

AT模式运行机制

     AT模式的特点就是对业务无入侵式,整体机制分二阶段提交。

     两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:
    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。

   在 AT 模式下,用户只需关注自己的业务SQL,用户的业务SQL 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。 

image-20210215181643407

这个模式需要模块为Java语言,并且数据库支持本地事务。一个典型的分布式事务过程: 

  • TM 向 TC 申请开启一个全局事务,全局事务创建并生成一个全局唯一的XID。
  • XID 在微服务调用链路的上下文中传播。
  • RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖。
  • TM 向 TC 发起针对 XID 的全局提交或回滚决议。
  • TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

springcloud整合seata实现分布式事务 

   操作步骤如下:     

  • 1.seata-server端,修改server配置
  • 2.client端(你自己的项目,TM和RM的配置),引入配置文件,修改配置文件
  • 3.数据源代理设置
  • 4.创建数据库表
  • 5.启动注册中心(eureka),启动server,启动client(包括订单服务,库存服务、账户服务)

1. seata-server端配置和启动

        1)下载安装seata

                阿里seata官网下载,直接解压到指定目录,先配置再启动,

                 seata-server中,/conf目录下,有两个配置文件,需要结合自己的情况来修改:

        2)修改conf/file.conf文件

                       ① 将mode="file"改为mode="db"    

1601303876143

                ② db部分配置mysql相关信息

db {
	DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    dbType = "mysql"
    //注意如果是mysql8版本,此处采用cj驱动,url后缀需要加serverTimezone=Asia/Shanghai
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://rm-bp17dq6iz79761b8fxo.mysql.rds.aliyuncs.com:3306/seata?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8"
    //用户名和密码
    user = "seata_test"
    password = "- seata1234abcd!"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

                ③ 数据库对应上述配置新建seata的DB,并分配给指定的用户权限                                                                                        

                ④ 初始化table,注意此处一定要初始化,并且1.0之后的版本没有sql脚本,这里贴出来

1601304565604

-- 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
-- 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;

1601304688564

        3)修改registry.conf文件

        这个文件内容分为registryconfig 2部分。

                ① 将registry和config部分的由type="file" 都换成type="nacos"(注意是2处地方)

                ② 将两处的nacos配置根据实际情况调整参数。

1601305065064

1601305025041

    nacos {
    application = "seata-server"
    serverAddr = "nacos.it235.com:80"
    group = "SEATA_GROUP"
    namespace = "343f2aa2-1a42-43ea-b078-33ab7d58bd6a"
    cluster = "default"
    username = "nacos"
    password = "nacos"
}

        4)修改conf/logback.xml的文件(可选操作)

        将${user.home}改为具体的seata目录,如F:\hliedu\cloud\seata-server-1.3.0\seata,那么配置如下:

<property name="LOG_HOME" value="F:\hliedu\cloud\seata-server-1.3.0\seata\logs"/>

        5)双击启动bin/seata-server.bat文件启动服务(有可能出现闪退)

        6)为了方便查看更加清晰的日志,建议使用cmd的方式启动

                ① 打开CMD窗口,使用cd命令切换到seatabin目录

                ② 输入seata-server.bat回车

        7)启动成功的结果如下

1601305597369

2. client端(TM和RM端)相关配置 

        1)导入相关依赖 spring-cloud-alibaba-seata

        2)各数据库加入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;

        3)application.yaml配置

                除了常规配置外,这里还要配置下事务组信息:                

spring:
    cloud:
        alibaba:
            seata:		
                # 这个fsp_tx_group自定义命名很重要,server,client都要保持一致
                tx-service-group: fsp_tx_group  

        4)file.conf和registry.conf的配置

                把seata-server中的这两个配置好的文件copy到resource目录下,做以下修改:

                        ① file.conf                        

service {
  #vgroup->rgroup
  # 这个fsp_tx_group自定义命名很重要,server,client都要保持一致    
  vgroup_mapping.fsp_tx_group = "default"   
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  disableGlobalTransaction = false
}

             registry.conf主要是配置注册中心,看情况做修改

        5)数据源代理

        这个是要特别注意的地方,seata对数据源做了代理和接管,在每个参与分布式事务的服务中,都要做如下配置:

        ① 取消数据源自动创建

// 在启动类中取消数据源的自动创建
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) //这个注解里添加exclude属性
@MapperScan("com.fly.demo.dao")
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(OrderServerApplication.class, args);
	}

}

        ② 自定义数据源配置

/**
 * 数据源代理
 * @author lrp
 */
@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*:/mapper/*.xml"));
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        return sqlSessionFactoryBean.getObject();
    }

}

   3. client端(RM和TM服务)实现

        1. 去掉每个服务的本地事务控制(一般是Service上加transitional注解)

        2. 在TM的业务类的全局事务的方法上加上GlobalTransaction注解

   4. 分布式事务举例

        有四个微服务模块:虚拟机模块、镜像模块、模板模块和网络模块。其中虚拟机的创建需要镜像、模块和网络。虚拟机的创建需要调用其他三个模块,此时创建虚拟机为一个全局事务(TM),其他三个模块都是资源(RM)。多个全局事务都被事务协调器(TC)管理。

        如上所述,任意一个RM报错,其他的RM仍能执行成功,此时undo_log表会记录更改前后的信息,seata-server会自动将这个TM回滚到更改前的状态。

    5. 关于seata-server启动时闪退问题

              1) 内存不足(一般出现较少),在seata-server.bat/seata-serve.sh的文件中配置运行内存大小

              2)没有logs文件夹,手动添加

              3)JRE的问题,当(1)和(2)都没问题时在考虑这一点。需要重装jdk,重装时,所有选项都要勾选。 

                  

         

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微服务是一种软件架构设计风格,旨在将一个复杂的应用程序拆分为多个彼此独立的小型服务,每个服务专注于执行特定的业务功能。Spring Cloud是一个开源框架,提供了一套工具和组件,用于构建和部署微服务架构。 Seata是一个开源的分布式事务解决方案,可以实现分布式事务的一致性和隔离性。它提供了一种简单的方式来管理和协调多个微服务之间的事务操作。 在微服务架构中,使用Seata实现分布式事务需要对Spring Cloud进行整合。这个过程包括以下几个步骤: 首先,需要在每个微服务的pom.xml文件中引入Seata的相关依赖。 其次,需要在每个微服务的配置文件中配置Seata相关的信息,包括Seata服务端的地址、端口等。 然后,需要在每个微服务的代码中添加Seata的注解,用于标记分布式事务的范围和边界。 接下来,需要在每个微服务的代码中使用Seata提供的API来进行事务管理,包括事务的开始、提交和回滚等操作。 最后,需要在每个微服务的代码中处理异常情况,例如当事务提交失败时的处理逻辑。 通过以上步骤,就可以将Seata整合Spring Cloud中,实现分布式事务的一致性和隔离性。这样,当多个微服务之间发生操作时,可以保证事务的正确执行,避免数据不一致的问题。 总而言之,通过将Spring CloudSeata整合,可以实现分布式事务的管理和协调,从而提高微服务架构的可靠性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值