springCloud整合seata

Seata 作为分布式事务解决方案,致力于提供高性能简单易用的分布式服务。Seata提供了AT、TCC、SAGA、XA事务模式,此处介绍的是AT模式。

传统的单体应用中,通常本地数据库(@Transactional)保证一致性和完整性,而分布式环境中,多个服务进行跨数据库操作,此时本地事务无法保证全局事务一致性,这就需要引入分布式事务来协调多个服务之间的操作,保证分布式系统数据一致性和可靠性。

分布式事务通常以下三个角色组成:

1、事务协调者(Transaction Coordinator):简称TC,就是Seata服务端,负责协调并管理分布式事务的执行。他是分布式事务的协调器,协调多个参与者的事务操作。事务协调者负责全局事务的创建、提交、回滚以及事务的状态管理。简单理解就是,整个事务管理的老大。

2、事务管理器(Transaction Manager):简称TM,服务管理应用程序的本地事务(分支事务)。事务管理器定义了全局事务的范围。负责将分支事务注册到全局事务中,并在全局事务的协调下,执行本地事务的提交或者回滚。简单理解就是,执行整个分布式事务的每个小的本地事务单元(小弟)

3、资源管理器(Resource Manager): 简称RM,管理分支事务的资源,与TC交谈以注册分支事务和报告分支事务的状态。简单理解就是资源,比如mysql,Oracle、消息队列、redis等。此处使用mysql。

不说这些理论了,直接开始。

一、首先是下载并安装Seata和nacos.

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

这里的seata服务是注册到nacos上,所以还需要下载nacos,nacos下载地址:

https://github.com/alibaba/nacos/releases。下载解压后,进入到nacos目录,打开bin文件夹,windows使用命令:startup.cmd -m standalone 启动nacos单机模式。

 二、在解压后的conf文件中找到application.yaml文件,参照application.example.yml文件。将相关连接信息改为你自己的,比如数据库连接改为你数据库的连接信息。

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${log.home:${user.home}/logs/seata}
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata
seata:
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848 #nacos地址
      namespace: qiu  #nacos上seataServer.properties所在命名空间
      group: DEFAULT_GROUP #nacos上seataServer.properties所在分组group
      username: nacos  #nacos账号 
      password: nacos  #nacos密码
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
      data-id: seataServer.properties  #seata服务器端在nacos上的配置文件
  registry:
    # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
    type: nacos
    #preferred-networks: 30.240.*
    nacos:
      application: seata-server  #注册到seata上的服务名称
      server-addr: 127.0.0.1:8848  #nacos地址
      group: DEFAULT_GROUP #注册到nacos上分组
      namespace: 4a00209c-f071-43eb-8ee0-30e929b6457a #注册到nacos所在命名空间
      cluster: default  #默认的即可
      username: nacos  #nacos账号
      password: nacos  #nacos密码
      context-path:
  store:
    # support: file 、 db 、 redis 、 raft
    mode: db  #数据库用db
    session:
      mode: db
    lock:
      mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true  #数据库连接地址
      user: root  #数据库账号
      password: root  #数据库密码
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000
      max-wait: 5000
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017  #不用去改变
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**

在nacos上建文件,名称为:seataServer.properties,内容如下:

store.mode=db
store.lock.mode=db
store.session.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true  # 数据库连接信息
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

注意:这个文件所在的命名空间,会影响application.yaml里面的配置信息

三、采用的是AT模式,数据库需要做两个操作

1、需要建个数据库,名字最好是seata,并且在里面去初始化四张表,这四张表结构,在seata解压包里面的\script\server\db文件夹下,有个mysql.sql文件。将其放到Navicat中执行到seata数据库中

 

2、在需要执行的微服务数据库(比如我此处是user库和category库都要添加这张表)中需要初始化一张undo_log表。表结构如下

CREATE TABLE `undo_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `branch_id` bigint NOT NULL,
  `xid` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,
  `context` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
  `rollback_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `log_status` int NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` date NOT NULL,
  `ext` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ux_undo_log` (`branch_id`,`xid`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLL

此处我把rollback_info字段类型改为varchar改为text,因为之前报过错误提示该字段长度不够。

四、启动seata服务端

打开seata解压文件夹,打开bin目录,双击seata-server.bat,启动成功后,访问http://localhost:7091/#/login ,能够看到下面页面说明seata服务端启动成功。

 然后去nacos上看下seata服务是否已经注册上去,在你的seata的application.yaml中配置的nacos命名空间下找到seata-server,说明已经注册成功

 五、seata客户端的使用配置

这里使用两个微服务模块,分别是catogory_mudule和user_module。只是个demo,微服务模块名称不必在乎

这两个微服务模块的配置信息:

1、添加依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

2、application.yaml配置信息如下:

seata:
  application-id: seata-demo-user  
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848  #nacos地址
      namespace: "4a00209c-f071-43eb-8ee0-30e929b6457a" #nacos上seata服务端所在命名空间
      group: DEFAULT_GROUP  #分组
      application: seata-server #seata服务端服务名称
      username: nacos
      password: nacos
  tx-service-group: seata_tx_group  #这个通常使用默认的
  service:
    vgroup-mapping:
      seata_tx_group: default
  data-source-proxy-mode: AT  #AT模式

六、代码中添加注解@GlobalTransactional

    @Override
    @GlobalTransactional
    public void testSeata(String username, String password, String deviceName) {
        // 当前服务数据
        UserInfo info = new UserInfo();
        info.setUserName(username);
        info.setPassword(password);
        boolean save = this.save(info);
        if (save){
            log.info("用户信息保存成功");
        }
        //int i = 1/0;
        Boolean device = categoryService.createDevice(deviceName);
        if (device){
            log.info("保存设备信息成功");
        }
    }

其中user为当前服务,category为远程调用category微服务模块,当然,此处你需要使用微服务调用组件feign或者openFeign。

另外好像我记得这个@GlobalTransactional只能加到serviceImpl层,不能添加到controller层,否则会失效。

结果:

如果此方法,两个微服务正常执行不报错,那么就提交事务保存到数据库

如果此方法发生错误,那么两个微服务的SQL都会进行回滚,数据库数据如旧。

保证了数据的可靠性和一致性。

 

相对而言,springcloud整合seata整体难度不大,但需要耐心点,配置好相关信息,基本都能正常使用。希望大家在学习和使用的路上一路顺风!!

 

posted @ 2024-02-26 11:29  多多指教~  阅读(56)  评论(0编辑  收藏  举报