irpas技术客

SpringCloud整合seata 纯file模式_全真教

网络 1604

第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://·piler.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://·piler.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来实现。

总结:要注意的点: pom依赖的时候,其实可以根本不需要排除。

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

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

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

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

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

全真教 包教会


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #纯file模式 #rm #F #Seata #Docker