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

SpringCloud整合seata 纯file模式_第1张图片

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

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

SpringCloud整合seata 纯file模式_第2张图片

父项目的pom文件内容:



    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.6.RELEASE
         
    
    pom
    
        common
        business-demo
        order-demo
        storage-demo
    
    4.0.0

    boss.zkt
    seata-base-file
    0.0.1

    
        8
        8
    
    
        
            org.projectlombok
            lombok
            1.18.12
        
    
    
        
            
                boss.zkt
                common
                0.0.1
            
            
                mysql
                mysql-connector-java
                8.0.20
            
            
            
                com.alibaba
                druid
                1.1.22
            
            
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                2.1.0
            
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                2.2.1.RELEASE
                pom
                import
            
            
                org.springframework.cloud
                spring-cloud-dependencies
                Hoxton.SR9
                pom
                import
            
        
    

SpringCloud整合seata 纯file模式_第3张图片

 SpringCloud整合seata 纯file模式_第4张图片

SpringCloud整合seata 纯file模式_第5张图片

这种方式的确可以成功实现,但是很多个微服务,复制粘贴代码很麻烦,主要是改一个,全部都得改,所以搞一个公共的模块配置,用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 cls = serviceProperties.getClass();

        Map 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的配置出错");
        }
    }
}

SpringCloud整合seata 纯file模式_第6张图片

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

SpringCloud整合seata 纯file模式_第7张图片

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

SpringCloud整合seata 纯file模式_第8张图片

其他微服务也一样。 

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



    
        boss.zkt
        seata-base-file
        0.0.1
    
    4.0.0
    common
    
        8
        8
    
    

        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            mysql
            mysql-connector-java
        
        
        
            com.alibaba
            druid
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        


        
        
            io.seata
            seata-spring-boot-starter
            1.4.2
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-seata
            
                
                    io.seata
                    seata-spring-boot-starter
                
            
        
    

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

SpringCloud整合seata 纯file模式_第9张图片

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

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

这里,我把多余的什么基于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

分别三张表:

SpringCloud整合seata 纯file模式_第10张图片

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依赖的时候,其实可以根本不需要排除。SpringCloud整合seata 纯file模式_第11张图片

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

3、file.conf中的default.grouplist  是无效的SpringCloud整合seata 纯file模式_第12张图片

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

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

SpringCloud整合seata 纯file模式_第13张图片

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

全真教 包教会

你可能感兴趣的:(Java从零到高薪就业,spring,分布式,架构)