SpringCloud整合seata 纯file模式

第1章:编写脚本start-seata.sh并且授权:

#!/bin/sh

docker rm -f   seata

docker run -d --privileged=true --restart always --name seata  --net=host --name seata -p8091:8091   seataio/seata-server:latest

授权可执行脚本文件:chmod +x ./start-seata.sh

直接启动脚本 ./start-seata.sh

查看启动效果: docker logs -f seata

第2章:搭建SpringCloud项目证明seata分布式事务

2.1【】这里先证明seata基于file文件的形式

父项目的pom文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <packaging>pom</packaging>
    <modules>
        <module>common</module>
        <module>business-demo</module>
        <module>order-demo</module>
        <module>storage-demo</module>
    </modules>
    <modelVersion>4.0.0</modelVersion>

    <groupId>boss.zkt</groupId>
    <artifactId>seata-base-file</artifactId>
    <version>0.0.1</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>boss.zkt</groupId>
                <artifactId>common</artifactId>
                <version>0.0.1</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.20</version>
            </dependency>
            <!-- druid数据源 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.22</version>
            </dependency>
            <!-- mybatis整合springboot -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.0</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.1.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

 

这种方式的确可以成功实现,但是很多个微服务,复制粘贴代码很麻烦,主要是改一个,全部都得改,所以搞一个公共的模块配置,用maven聚合到项目里边,就简单多了。

那到底怎么做呢?创建一个common的模块。

对所有微服务,进行统一注册nacos。

所以编写一个公共的NacosCommonConfig,等会全部微服务引用这个模块。

package boss.zkt.config.nacos;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.core.env.Environment;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;

/**
 * creator:全真教
 * date: 2020/4/27
 */
@SpringBootConfiguration
@Slf4j
public class NacosCommonConfig {
    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;// 这种方式是比较方式,看源码出来
    @Resource
    Environment environment;
    @PostConstruct
    public void initNacos() {
        String appName = environment.getProperty("spring.application.name");// 拿到微服务的名字
        String serverAddr = "你的地址:8848";//开发环境用测试服务器的公网
        String[] activeProfiles = environment.getActiveProfiles();
        if (activeProfiles.length > 0) {
            if ("pro".equals(activeProfiles[0])) {
                serverAddr = "172.16.25.162:8848";// 正式环境的私网
            } else if ("dev".equals(activeProfiles[0])) {
                serverAddr = "你的地址:8848";// 开发环境用测试服务器的公网
//                nacosDiscoveryProperties.setWatchDelay(2000L);// 从nacos获取服务列表的频率(2秒一次)
//                nacosDiscoveryProperties.setHeartBeatInterval(1);// 给nacos发送心跳的时间间隔
//                nacosDiscoveryProperties.setHeartBeatTimeout(3);// nacos多少秒没有收到这个心跳,就直接把这个微服务删除
            }else if("test".equals(activeProfiles[0])){
                serverAddr = "你的地址:8848";// 开发环境用测试服务器的公网
            }
        }
        log.warn("#######" + appName + ":配置nacos的环境" + (activeProfiles.length > 0 ? activeProfiles[0] : "无配置") + "地址:" + serverAddr);
        try {
            InetAddress addr = InetAddress.getLocalHost();
            nacosDiscoveryProperties.setPassword("nacos");
            nacosDiscoveryProperties.setUsername("nacos");
            nacosDiscoveryProperties.setIp(addr.getHostAddress());
            log.warn("服务器获取自身ip地址成功:" + addr.getHostAddress());
        } catch (UnknownHostException e) {
            log.warn("服务器获取自身ip地址失败,将采用自动获取ip地址");
        }
        nacosDiscoveryProperties.setPort(Integer.parseInt(Objects.requireNonNull(environment.getProperty("server.port"))));
        nacosDiscoveryProperties.setServerAddr(serverAddr);
    }
}

如此之外,seata也应该配置相同的配置文件:SeataCommonConfig

 

package boss.zkt.config.seata;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import io.seata.spring.boot.autoconfigure.properties.SeataProperties;
import io.seata.spring.boot.autoconfigure.properties.SpringCloudAlibabaConfiguration;
import io.seata.spring.boot.autoconfigure.properties.client.ServiceProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author:牧牛者 说明:
 */
@SpringBootConfiguration
@Slf4j
public class SeataCommonConfig {
    @Resource
    private SeataProperties seataProperties;

    @Resource
    private InitializingBean serviceProperties; // 这里是动态代理生成的,所以只能注入接口。


    /**
     * 默认 情况 seata会先加载 SpringCloudAlibabaConfiguration 的txServiceGroup 默认就是
     * spring.application.name-seata-service-group 显然是不行的
     * 所以这里不让SpringCloudAlibabaConfiguration 先产生,应该在我们SeataProperties 实例 之后产生
     * // 只是为了 SpringCloudAlibabaConfiguration 实例延后产生
     */
    @Component
    @Primary
    @DependsOn(value = {"serviceProperties"})
    class MySpringCloudAlibabaConfiguration extends SpringCloudAlibabaConfiguration {
    }

    @PostConstruct
    private void initSeataConfig() {
        String txServiceGroup = "my_test_tx_group";// 这里跟你file.conf中的一致
//        springCloudAlibabaConfiguration.setTxServiceGroup("my_test_tx_group");
        seataProperties.setTxServiceGroup(txServiceGroup);
        // 同样的,这里是动态代理生成的,所以原本的类没有加入内存,所以只能拿到实例,用反射获取动态代理的类
        // 然后用反射获取 设置 seata服务器地址的方法,注意方法的参数是Map.class
        Class<? extends InitializingBean> cls = serviceProperties.getClass();

        Map<String, String> grouplist = new HashMap<>();
        grouplist.put("default", "你的地址:8091");
        try {
            Method setGrouplist = cls.getDeclaredMethod("setGrouplist", Map.class);
            setGrouplist.invoke(serviceProperties, grouplist);
        } catch (Exception e) {
            log.error("seata的配置出错");
        }
    }
}

后把这个模块在父级pom中声明:

然后再把这个模块引入到其他的微服务:分别是business、order、storage微服务:

其他微服务也一样。 

注意:common模块里边不仅仅有我们自己的配置,还有SpringCloud的和Spring cloud  For alibaba 还有数据库链接池、mybatis、mysql驱动等,所以common的pom文件是这个样子:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>boss.zkt</groupId>
        <artifactId>seata-base-file</artifactId>
        <version>0.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>common</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>

        <!--   nacos的注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!-- mybatis整合springboot -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>


        <!-- https://mvnrepository.com/artifact/io.seata/seata-all -->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.4.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

同样的,在common模块中创建resources资源文件,把file.conf和registry.conf 这个两个文件放进去。

 这样就不用把这个文件复制到每个微服务了。

接下来就是改这两个文件了。如果你是从官网下载的,那么这两个文件,压根不用改,什么都不用改。直接就可以用。

这里,我把多余的什么基于nacos、zk、eureka等的配置全部删了,这样看起来简洁点:

registry.conf:

registry {
    type = "file"
  file {
    name = "file.conf"
  }
}

config {
  type = "file"
  file {
    name = "file.conf"
  }
}

file.conf:只需要改一个地方:或者不改:vgroup_mapping.my_test_tx_group = "default"
my_test_tx_group 改成你想要的,但是要注意跟yml中一致,切记哦

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the client batch send request enable
  enableClientBatchSendRequest = true
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  # my_test_tx_group 这个字段一定要跟yml或者你自己定义的公共配置类里边的哪个事务分组字段一样
  vgroup_mapping.my_test_tx_group = "default"
  # 这个配置在这里是无法生效的,配了也是白配(这是个坑),请在yml文件或者自定义配置类里边去配置
  default.grouplist = "39.103.154.143:8091"

  enableDegrade = false

  disableGlobalTransaction = false
}

client {
  rm {
    asyncCommitBufferLimit = 10000
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
  }
  undo {
    dataValidation = true
    logSerialization = "jackson"
    logTable = "undo_log"
  }
  log {
    exceptionRate = 100
  }
}

好了,接下来准备数据库和数据表:

三个数据库,business_db、seata_order_db、seata_storage_db

分别三张表:

undo_log的sql:

CREATE TABLE `undo_log`  (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `branch_id` bigint(20) NOT NULL,

  `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,

  `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,

  `rollback_info` longblob NOT NULL,

  `log_status` int(11) NOT NULL,

  `log_created` datetime(0) NOT NULL,

  `log_modified` datetime(0) NOT NULL,

  PRIMARY KEY (`id`) USING BTREE,

  UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


如果库存多了,订单表也不会插入数据。

2.2【】启动服务:postman测试

就实现了分布式事务了

以上主要是讲解了搭建seata整合springCloud,官放的文档在我看来有些地方写的有歧义,再加上版本变来变去,容易混淆,于是搞了这个文章,帮助那些整和seata遇到坑的朋友。

官方说了,如果seata实用单机服务器,那么file模式性能跟高。后面将实用nacos来实现。

总结:要注意的点:

  1. pom依赖的时候,其实可以根本不需要排除。

2、建议不要用seata-all依赖的方式,seata-spring-boot-starter方式简

3、file.conf中的default.grouplist  是无效的

4、vgroup_mapping.my_test_tx_group 这里的事务名称要跟你yml或者自定义配置的公共类中事务名称一致。

5、SpringCloudAlibabaConfiguration 会先启动,就默认获取的事务组名称很坑,让他后启动。

 其他的就是maven聚合时候要注意的一些版本号,依赖传递,聚合的事情了。我把全部要注意的点都讲清楚了,希望你一次搞定,一次实现分布式事务控制。

全真教 包教会

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Cloud和Seata都是分布式系统开发中常用的框架,它们可以一起使用来实现分布式事务管理。下面是Spring Cloud整合Seata的步骤: 1. 引入Seata的依赖 在Spring Boot项目的pom.xml文件中,添加Seata的依赖: ```xml <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>${seata.version}</version> </dependency> ``` 其中${seata.version}需要根据实际情况进行替换。 2. 配置Seata的配置文件 在Spring Boot项目的resources目录下,创建一个名为file.conf的文件,并配置Seata的全局配置信息。示例如下: ```ini transport.type=TCP transport.server=NIO transport.heartbeat=true transport.enableClientBatchSendRequest=false transport.threadFactory.bossThreadPrefix=NettyBoss transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler transport.threadFactory.shareBossWorker=false transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector transport.threadFactory.clientSelectorThreadSize=1 transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread transport.threadFactory.bossThreadSize=1 transport.threadFactory.workerThreadSize=default transport.shutdown.wait=3 service.vgroupMapping.my_test_tx_group=default service.seata.grouplist[default]=localhost:8091 client.rm.async.commit.buffer.limit=10000 client.rm.lock.retryInterval=10 client.rm.lock.retryTimes=30 client.rm.report.retryCount=5 client.rm.report.success.enable=false client.rm.table.meta.check.enable=false client.rm.table.undo.data.validation=false ``` 其中,service.vgroupMapping.my_test_tx_group是指将分布式事务组名为my_test_tx_group的应用程序映射到default分组,service.seata.grouplist[default]是指定Seata Server的地址和端口号。 3. 配置Spring Cloud的数据源 在Spring Boot项目中,需要将数据源配置为Seata的代理数据源。在application.properties或application.yml文件中,添加以下配置: ```yaml spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false spring.datasource.username=root spring.datasource.password=root # Seata DataSourceProxy spring.cloud.alibaba.seata.tx-service-group=my_test_tx_group spring.cloud.alibaba.seata.enable-auto-data-source-proxy=true ``` 其中,spring.datasource.*是指定应用程序使用的数据源,spring.cloud.alibaba.seata.*是指定使用Seata代理数据源。 4. 配置Spring Cloud的Feign客户端 如果应用程序中使用了Feign客户端,则需要配置Feign客户端的拦截器,以便在进行远程调用时启用Seata分布式事务管理。在Spring Boot项目中,需要定义一个名为FeignConfiguration的类,并在其中添加以下配置: ```java @Configuration public class FeignConfiguration { @Bean public RequestInterceptor requestInterceptor() { return new SeataFeignClientInterceptor(); } } ``` 其中,Seata

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菩提老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值