纵观全文

  • 项目简介
  • 配置Seata Server服务
    • 修改conf下的registry.conf文件
    • 修改conf下的file.conf文件
    • 启动seata server服务
  • 在系统服务中配置使用Seata
    • 1、首先通过maven引入seata依赖
    • 2、对应的service需要在resources目录下添加registry.conf和file.conf文件
    • 3、修改对应微服务下的application.yml配置文件
    • 4、创建数据库undo_log表
    • 5、将数据源交于druid自动配置(必须)
  • 编写测试用例
  • 测试seata分布式事务
    • 模拟cloud-iqs失败
    • 模拟cloud-usc失败
    • 模拟成功

项目简介

项目使用Spring Cloud 分布式框架,使用过程中,客户提出了购买物品时,调用库存微服务,使用库存后,调用支付微服务失败,库存数据未正常回滚,导致数据两边数据不一致的问题。因此决定引入阿里的分布式事务Seata。
本文边详细的介绍一下整合的过程,以及整合过程中遇到的问题。

  • 项目使用到的框架版本
  • SpringBoot : 1.5.13.RELEASE
  • SpringCloud : Edgware.SR3
  • SpringCloud Alibaba : 1.5.1.RELEASE
  • mybatis-plus : 3.1.0
  • druid : 1.1.12
  • seata : 0.9.0
  • mysql : 8.0

选择对应的版本
可以在 Github上spring-cloud-alibaba的开源项目找到SpringCloud对应的seata版本

找到项目对应的版本后,下载对应的seata server,下载地址:https://github.com/seata/seata/releases

  • windows下载 seata-server-0.9.0.zip
  • Linux下载 seata-server-0.9.0.tar.gz

配置Seata Server服务

下载完对应的版本后, 将其解压。可以看到内容如下:

  • bin:主要放置Seata server的启动文件
  • conf:主要放置Seata server的配置文件和数据库表结构
  • lib:主要放置一些依赖的jar包

conf的目录如下:

  • db_undo_log.sql:初始化的数据库的表结构
  • file.conf:Seata server的配置文件
  • registry.conf:Seata server注册的配置文件

修改conf下的registry.conf文件

registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "eureka"  # 修改这里,这里我使用的时eureka注册中心,对应下面的eureka配置,其他的配置信息可删除nacos {serverAddr = "localhost"namespace = ""cluster = "default"}# 修改这里,因为上面用的是eureka,需要配置下面的eureka注册信息eureka {serviceUrl = "http://127.0.0.1:8761/eureka"application = "seata-server"weight = "1"}redis {serverAddr = "localhost:6379"db = "0"}zk {cluster = "default"serverAddr = "127.0.0.1:2181"session.timeout = 6000connect.timeout = 2000}consul {cluster = "default"serverAddr = "127.0.0.1:8500"}etcd3 {cluster = "default"serverAddr = "http://localhost:2379"}sofa {serverAddr = "127.0.0.1:9603"application = "default"region = "DEFAULT_ZONE"datacenter = "DefaultDataCenter"cluster = "default"group = "SEATA_GROUP"addressWaitTime = "3000"}file {name = "file.conf"}
}config {# file、nacos 、apollo、zk、consul、etcd3type = "file" # 这里使用file的配置文件,其余的可以删除掉nacos {serverAddr = "localhost"namespace = ""}consul {serverAddr = "127.0.0.1:8500"}apollo {app.id = "seata-server"apollo.meta = "http://192.168.1.204:8801"}zk {serverAddr = "127.0.0.1:2181"session.timeout = 6000connect.timeout = 2000}etcd3 {serverAddr = "http://localhost:2379"}# 使用conf下的file.conf配置file {name = "file.conf"}
}

修改conf下的file.conf文件

transport {# tcp udt unix-domain-sockettype = "TCP"#NIO NATIVEserver = "NIO"#enable heartbeatheartbeat = true#thread factory for nettythread-factory {boss-thread-prefix = "NettyBoss"worker-thread-prefix = "NettyServerNIOWorker"server-executor-thread-prefix = "NettyServerBizHandler"share-boss-worker = falseclient-selector-thread-prefix = "NettyClientSelector"client-selector-thread-size = 1client-worker-thread-prefix = "NettyClientWorkerThread"# netty boss thread size,will not be used for UDTboss-thread-size = 1#auto default pin or 8worker-thread-size = 8}shutdown {# when destroy server, wait secondswait = 3}serialization = "seata"compressor = "none"
}
service {#vgroup->rgroupvgroup_mapping.my_test_tx_group = "seata-server"  # 修改这里,registry.conf文件里的eureka的application#only support single nodedefault.grouplist = "127.0.0.1:8091" # 修改这里,这里是seata的默认端口号,启动的时候可以指定端口号,记得对应#degrade current not supportenableDegrade = false#disabledisable = false#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanentmax.commit.retry.timeout = "-1"max.rollback.retry.timeout = "-1"
}client {async.commit.buffer.limit = 10000lock {retry.internal = 10retry.times = 30}report.retry.count = 5tm.commit.retry.count = 1tm.rollback.retry.count = 1
}## transaction log store
store {## store mode: file、dbmode = "file"  # 这里使用的是file## file storefile {dir = "sessionStore"# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptionsmax-branch-session-size = 16384# globe session size , if exceeded throws exceptionsmax-global-session-size = 512# file buffer size , if exceeded allocate new bufferfile-write-buffer-cache-size = 16384# when recover batch read sizesession.reload.read_size = 100# async, syncflush-disk-mode = async}## database storedb {## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.datasource = "druid"## mysql/oracle/h2/oceanbase etc.db-type = "mysql"driver-class-name = "com.mysql.cj.jdbc.Driver"url = "jdbc:mysql://192.168.0.65:3306/core"user = "root"password = "123456"min-conn = 1max-conn = 3global.table = "global_table"branch.table = "branch_table"lock-table = "lock_table"query-limit = 100}
}
lock {## the lock store mode: local、remotemode = "remote"local {## store locks in user's database}remote {## store locks in the seata's server}
}
recovery {#schedule committing retry period in millisecondscommitting-retry-period = 1000#schedule asyn committing retry period in millisecondsasyn-committing-retry-period = 1000#schedule rollbacking retry period in millisecondsrollbacking-retry-period = 1000#schedule timeout retry period in millisecondstimeout-retry-period = 1000
}transaction {undo.data.validation = trueundo.log.serialization = "jackson"undo.log.save.days = 7#schedule delete expired undo_log in millisecondsundo.log.delete.period = 86400000undo.log.table = "undo_log"
}## metrics settings
metrics {enabled = falseregistry-type = "compact"# multi exporters use comma dividedexporter-list = "prometheus"exporter-prometheus-port = 9898
}support {## springspring {# auto proxy the DataSource beandatasource.autoproxy = false}
}

启动seata server服务

进入bin目录,如果使用的eureka,需要先启动eureka server注册中心,使用其他的,也需要先启动

linux下启动seata server: -p 后面可以指定seata server启动的端口号

nohup sh seata-server.sh -p 8091 &

启动后可以看到

windows启动直接双击。

启动后查看eureka是否注册到eureka注册中心。

在系统服务中配置使用Seata

1、首先通过maven引入seata依赖

在pom.xml的dependencyManagement下引用spring-cloud-alibaba

<!-- 引入seata依赖 -->
<dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-seata</artifactId><version>1.5.1.RELEASE</version></dependency>
</dependencies><!-- 引入spring-cloud-alibaba-->
<dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>1.5.1.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependencies>
</dependencyManagement>

2、对应的service需要在resources目录下添加registry.conf和file.conf文件

文件对应内容如下:

  • registry.conf
registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "eureka"eureka {serviceUrl = "http://127.0.0.1:8761/eureka"   # 注意这里,对应eureka注册中心application = "seata-server"                  # 注意这里,对应registry.conf文件里的eureka的applicationweight = "1"}
}config {# file、nacos 、apollo、zk、consul、etcd3type = "file"file {name = "file.conf"}
}
  • file.conf
transport {# tcp udt unix-domain-sockettype = "TCP"#NIO NATIVEserver = "NIO"#enable heartbeatheartbeat = true#thread factory for nettythread-factory {boss-thread-prefix = "NettyBoss"worker-thread-prefix = "NettyServerNIOWorker"server-executor-thread-prefix = "NettyServerBizHandler"share-boss-worker = falseclient-selector-thread-prefix = "NettyClientSelector"client-selector-thread-size = 1client-worker-thread-prefix = "NettyClientWorkerThread"# netty boss thread size,will not be used for UDTboss-thread-size = 1#auto default pin or 8worker-thread-size = 8}shutdown {# when destroy server, wait secondswait = 3}serialization = "seata"compressor = "none"
}
service {#vgroup->rgroupvgroup_mapping.my_test_tx_group = "seata-server"   # 注意这里,对应registry.conf文件里的eureka的application#only support single nodedefault.grouplist = "127.0.0.1:8761:8091"          # 修改这里,对应seata server的ip和端口号#degrade current not supportenableDegrade = false#disabledisable = false
}client {async.commit.buffer.limit = 10000lock {retry.internal = 10retry.times = 30}report.retry.count = 5tm.commit.retry.count = 1tm.rollback.retry.count = 1
}
transaction {undo.data.validation = trueundo.log.serialization = "jackson"undo.log.save.days = 7#schedule delete expired undo_log in millisecondsundo.log.delete.period = 86400000undo.log.table = "undo_log"
}support {## springspring {# auto proxy the DataSource beandatasource.autoproxy = false}
}

3、修改对应微服务下的application.yml配置文件

spring:cloud:alibaba:seata:tx-service-group: my_test_tx_group

4、创建数据库undo_log表

在每个业务库中创建以下数据库表,表明可以修改,修改后记得修改对应的配置

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

5、将数据源交于druid自动配置(必须)

禁用Springboot的dataSources自动装配,在启动项添加以下配置

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

创建dataSources数据源控制:DataSourceConfig.java

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;@Configuration
public class DataSourceConfig {@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);}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();// 配置mybatis-plus的分页PaginationInterceptor paginationInterceptor = new PaginationInterceptor();Interceptor[] plugins = {paginationInterceptor};sqlSessionFactoryBean.setPlugins(plugins);sqlSessionFactoryBean.setDataSource(dataSourceProxy);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*.xml"));// 配置spring的本地事务sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());// 配置mybatis-plus的逻辑删除sqlSessionFactoryBean.setGlobalConfig(new GlobalConfig().setSqlInjector(new LogicSqlInjector()));// 配置mybatis-plus的log打印MybatisConfiguration cfg = new MybatisConfiguration();cfg.setJdbcTypeForNull(JdbcType.NULL);cfg.setMapUnderscoreToCamelCase(true);cfg.setCacheEnabled(false);cfg.setLogImpl(StdOutImpl.class);sqlSessionFactoryBean.setConfiguration(cfg);return sqlSessionFactoryBean.getObject();}
}

编写测试用例

准备两个测试的微服务(cloud-iqs,cloud-usc),这里只是测试效果用,实际根据业务需求来。

编写controller:

@ApiOperation("test seata, flag为1,正常提交  为2:cloud-iqs失败, 为3:cloud-usc失败")
@GetMapping("/testSeata")
public R testSeata(int flag){purOrderService.testSeata(flag);return R.ok();
}

编写service:

// seata分布式无使用GlobalTransactional注解
@GlobalTransactional
@Override
public void testSeata(int flag) {System.out.println(RootContext.getXID());TransExpense transExpense = new TransExpense();transExpense.setType("111");transExpenseMapper.insert(transExpense);// 通过fegin调用cloud-uscR r =  uscFeginClient.testSeata(flag);if(r.getCode() != 200){throw new RuntimeException(r.getMsg());}if(flag == 2){throw new RuntimeException("cloud-iqs fail");}
}

编写fegin:

@GetMapping(value = "user/testSeata", consumes = MediaType.ALL_VALUE)
R testSeata(@RequestParam("flag") int flag);

编写fegin调用的controller:

@ApiOperation(value = "testSeata")
@GetMapping(value = "testSeata")
public R testSeata(int flag){System.out.println("----------------------------------------------------user");User user = new User();user.setAccount(new Date().toString());user.setPassword("22222222222");userService.save(user);if(flag == 3){throw new RuntimeException("cloud-usc fail");}return R.ok();
}

测试seata分布式事务

模拟cloud-iqs失败

使用swagger2调用

查看数据库对应表结构:

usc库:

iqs库:

模拟cloud-usc失败

使用swagger2调用

查看数据库对应表结构:

usc库:

iqs库:

模拟成功

使用swagger2调用

查看数据库对应表结构:

usc库:


iqs库:

本文到此结束了,后续文章会陆续更新,文档会同步在CSDN和GitHub保持同步更新。有问题请留言

CSDN:https://blog.csdn.net/qq_34988304/category_8820134.html

Github文档:https://github.com/hack-feng/Java-Notes/tree/master/src/note/SpringCloud

GitHub源码:https://github.com/hack-feng/Spring-Cloud-Edgware.git

【实践篇】SpringCloud + Eureka + Mybatis plus 整合分布式事务Seata相关推荐

  1. SpringCloudAlibaba 微服务整合分布式事务Seata

    基于AT模式 创建undo_log(回滚日志表)表, 每个数据库需要创建 注意:UNDO_LOG Table:不同数据库在类型上会略有差别.详见官网 -- 注意此处0.7.0+ 增加字段 contex ...

  2. eureka server配置_springcloud+eureka整合分布式事务中间件seata

    今天继续给大家分享一下阿里的分布式事务中间件seata的使用,跟上篇文章<springboot多数据源整合分布式事务中间件seata>不一样的是,上篇文章是单服务绑定多数据源的分布式情况, ...

  3. springboot整合oracle_SpringBoot2.x系列教程67--Spring Boot整合分布式事务简介

    SpringBoot2.x系列教程67--Spring Boot整合分布式事务简介 作者:一一哥 一. 分布式事务简介 1. 什么是分布式事务 百度百科对分布式事务的解释如下: 分布式事务就是指事务的 ...

  4. Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案

    Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案 说明:Java生鲜电商平台中由于采用了微服务架构进行业务的处理,买家,卖家,配送,销售,供应商等进行服务化,但是不可避免存在 ...

  5. channelfuture怎么拿到数据_SpringBoot2.x系列教程66--Spring Boot整合分布式事务之数据库事务回顾

    SpringBoot2.x系列教程66--Spring Boot整合分布式事务之数据库事务回顾 作者:一一哥 本节主要内容 一. 事务出现的原因 转账是生活中常见的操作,比如从A账户转账100元到B账 ...

  6. getprivateprofilestring读不到数据_SpringBoot2.x系列教程66--Spring Boot整合分布式事务之数据库事务回顾

    SpringBoot2.x系列教程66--Spring Boot整合分布式事务之数据库事务回顾 作者:一一哥 本节主要内容 一. 事务出现的原因 转账是生活中常见的操作,比如从A账户转账100元到B账 ...

  7. SpringCloud Alibaba实战第九课 分布式事务理论、DevOps运维

    22 一致性挑战:微服务架构下的数据一致性解决方案 上一讲我们介绍了如何在微服务架构中设计统一的用户认证方案.本讲咱们填之前埋下的一个坑,如何在微服务架构下有效保障数据一致性问题.本讲咱们涉及三方面内 ...

  8. 微服务-分布式事务seata

    什么是分布式事务 单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源, 业务操作需要调用三个服务来完成.此时每个服务内部的数据一致性由本地事务来保证,但是全局的 ...

  9. 分布式事务 seata 最全入门教程

    基本介绍 什么是分布式事务 指一次大的操作由不同的小操作组成的,这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败.从本质上来说,分布式事务就是为了保证不同数据库 ...

最新文章

  1. 手机端html5展示pdf,pdf.js移动端展示预览打开pdf-pdfh5.js
  2. (005) java后台开发之Mac终端命令运行java
  3. C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
  4. PIC单片机精通_串口通信模块C实现
  5. stack heap java_java中的Heap 和 Stack | 学步园
  6. 删除VS.NET起始页上项目名称的方法.
  7. python使用scrapy_Python实现从脚本里运行scrapy的方法
  8. java Unicode转UTF-8代码
  9. 蓝桥杯2016年第七届C++省赛B组第五题-抽签
  10. 安装vs2013以后,链接数据库总是报内存损坏,无法写入的错误
  11. 在Intellij idea中快速重写父类方法
  12. 通过脚本执行sql语句
  13. 查看tomcat目前用的jdk版本
  14. 皮尔逊/斯皮尔曼相关系数
  15. 百度ueditor编辑器控制图片在编辑框中的大小
  16. 抖音很火的小程序表白html,最近抖音很火的表白小程序写法C#版
  17. Python调用百度API进行人像动漫化
  18. 亿图脑图MindMaster思维导图及亿图图示会员-骨折啦
  19. 微信域名被屏蔽被封了的解决办法 微信网址被屏蔽了红了照样打开
  20. compose安装单个扩展_将自动化测试扩展到单个项目之外

热门文章

  1. html修改svg颜色
  2. Java-黑马Java学习练习-day10字符串
  3. L2TP LAC initial 配置与安全策略
  4. 如何撰写开题的文献综述
  5. java怒之铁拳,经典游戏《怒之铁拳》那些有趣的设定,资深玩家们表示白玩了...
  6. 大厂高频面试题之Java并发核心AQS源码详解
  7. 这一辈子没法做太多的事情,所以每一件都要做得精彩绝伦
  8. 【django】用户注册时短信验证码校验、避免频繁发送短信验证码【17】
  9. JQ插件:Knob旋钮按钮
  10. 用vue仿美团APP