Spring Cloud Alibaba Seata 实现分布式事物

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案

Seata 官网:https://seata.io/zh-cn/

Spring Cloud Alibaba 官网:https://sca.aliyun.com/zh-cn/

版本说明

SpringBoot 版本 2.6.5

SpringCloud 版本 2021.0.1

SpringCloudAlibaba 版本 2021.0.1.0

读者可以先看笔者前面写的文章《Spring Cloud Gateway 使用 Redis 限流使用教程》,里面有创建项目的详细版本说明,这篇seata的文章是在 gateway 限流的项目基础上创建的

本文详细说明

数据库服务器版本 mysql 8.0.25

mybatis plus 版本 3.5.1

nacos 版本 1.4.2

seata 客户端版本 1.4.2

seata 服务端版本 1.7.1,笔者在文章最后面会使用服务端版本 1.4.2 演示,这里使用1.7.1版本的原因是1.4.2版本没有web控制台,且配置没有1.7.1方便,目前1.7.1版本是最新版

目录

1、创建项目

1.1、新建 maven 聚合项目 cloud-learn

1.2、创建 account 服务

1.3、创建 order 服务

2、添加配置

2.1、客户端配置

2.2、服务端配置

3、数据库建表

3.1、seata 服务端建表

3.2、seata 客户端建表

4、运行测试

5、Seata Server 1.4.2

6、项目代码


1、创建项目

1.1、新建 maven 聚合项目 cloud-learn

最外层父工程 cloud-learn 的 pom.xml

<?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"><modelVersion>4.0.0</modelVersion><groupId>com.wsjzzcbq</groupId><artifactId>cloud-learn</artifactId><version>1.0-SNAPSHOT</version><modules><module>gateway-learn</module><module>consumer-learn</module><module>sentinel-learn</module><module>seata-at-account-learn</module><module>seata-at-order-learn</module></modules><packaging>pom</packaging><repositories><repository><id>naxus-aliyun</id><name>naxus-aliyun</name><url>https://maven.aliyun.com/repository/public</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></repository></repositories><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.5</version><relativePath/></parent><properties><spring-cloud.version>2021.0.1</spring-cloud.version><spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version><alibaba-nacos-discovery.veriosn>2021.1</alibaba-nacos-discovery.veriosn><alibaba-nacos-config.version>2021.1</alibaba-nacos-config.version><spring-cloud-starter-bootstrap.version>3.1.1</spring-cloud-starter-bootstrap.version><druid.version>1.1.17</druid.version><mysql.version>8.0.11</mysql.version><mybatis-plus.version>3.5.1</mybatis-plus.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>${alibaba-nacos-discovery.veriosn}</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>${alibaba-nacos-config.version}</version></dependency><!--spring-cloud-dependencies 2020.0.0 版本不在默认加载bootstrap文件,如果需要加载bootstrap文件需要手动添加依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId><version>${spring-cloud-starter-bootstrap.version}</version></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.40</version></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>

下面会创建2个服务 account 和 order,模拟用户下订单后扣减账户金额,服务间使用 feign 调用,因为 account 和 order 服务使用不同的数据库,因此产生分布式事物,使用 seata 解决

seata 默认使用 AT 事物模型,本文讲解演示的就是 AT 事物模型,其他事物模型在后面的文章中讲解

1.2、创建 account 服务

创建子工程 seata-at-account-learn

seata-at-account-learn 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><artifactId>cloud-learn</artifactId><groupId>com.wsjzzcbq</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata-at-account-learn</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

启动类 SeataATAccountApplication

package com.wsjzzcbq;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** SeataATAccountApplication** @author wsjz* @date 2023/10/14*/
@MapperScan(value = {"com.wsjzzcbq.mapper"})
@SpringBootApplication
public class SeataATAccountApplication {public static void main(String[] args) {SpringApplication.run(SeataATAccountApplication.class, args);}
}

实体类 Account

package com.wsjzzcbq.bean;import lombok.Data;/*** Account** @author wsjz* @date 2022/07/07*/
@Data
public class Account {private Integer id;private String userId;private Integer money;
}

 AccountMapper

package com.wsjzzcbq.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wsjzzcbq.bean.Account;/*** AccountMapper** @author wsjz* @date 2023/10/13*/
public interface AccountMapper extends BaseMapper<Account> {
}

AccountService

package com.wsjzzcbq.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.wsjzzcbq.bean.Account;/*** AccountService** @author wsjz* @date 2023/10/13*/
public interface AccountService extends IService<Account> {String reduce(String userId, int money);
}

AccountServiceImpl

package com.wsjzzcbq.service.impl;import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsjzzcbq.bean.Account;
import com.wsjzzcbq.mapper.AccountMapper;
import com.wsjzzcbq.service.AccountService;
import io.seata.core.context.RootContext;
import org.springframework.stereotype.Service;/*** AccountServiceImpl** @author wsjz* @date 2023/10/13*/
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {@Overridepublic String reduce(String userId, int money) {String xid = RootContext.getXID();System.out.println(xid);UpdateWrapper<Account> up = new UpdateWrapper<>();String sql = "money = money - " + money;up.setSql(sql);up.eq("user_id", userId);this.update(up);return "ok";}
}

AccountController

package com.wsjzzcbq.controller;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wsjzzcbq.bean.Account;
import com.wsjzzcbq.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** AccountController** @author wsjz* @date 2023/10/13*/
@RequestMapping("/account")
@RestController
public class AccountController {@Autowiredprivate AccountService accountService;@GetMapping("/find")public String find() throws JsonProcessingException {Account account = accountService.list().get(0);ObjectMapper objectMapper = new ObjectMapper();String res = objectMapper.writeValueAsString(account);System.out.println(res);return res;}@RequestMapping("/reduce")public String debit(String userId, int money) {try {accountService.reduce(userId, money);return "扣款成功";} catch (Exception e) {return "扣款失败";}}
}

application.yml 文件

server:port: 9001
spring:application:name: seata-at-account-learndatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.3.232:3306/pmc-account?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456cloud:nacos:username: nacospassword: nacosserver-addr: 192.168.2.140discovery:namespace: public
#        server-addr: 192.168.2.140
#      config:
#        server-addr:seata:config:type: nacosnacos:server-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}group: SEATA_GROUPdata-id: seata.propertiesregistry:type: nacosnacos:application: seata-servercluster: defaultserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}group: SEATA_GROUP
# 事物分组,如果不配置默认是spring.application.name + '-seata-service-group'
#  tx-service-group:logging:level:com.wsjzzcbq.mapper: debugmybatis-plus:global-config:db-config:id-type: auto

关键配置说明

nacos 注册中心和配置中心默认从 spring.cloud.nacos.server-addr 中获取,因此可以配置一个

seata config 和 registry,config是客户端在nacos config 中存放的配置文件,它的 group 是 SEATA_GROUP,data-id 是 seata.properties,当然 group 和 data-id 名称是任意自定义的,但要保证和 nacos 中的对应上,否则找不到配置,seata.properties 具体配置内容后面详细说明;registry 配置的是nacos 中seata server 的信息,seata 客户端通过nacos 注册中心中配置的 seata server 的信息获取 seata server 实例,进行连接,这里笔者配置的 seata server group 是 SEATA_GROUP,seata server 的服务名是 seata-server,其实,可以把 seata server 理解为注册在nacos中的服务,相同的服务名,多个实例。项目启动后,会在nacos 注册中心中寻找服务名为 seata-server 的 seata 服务器,seata config、registry、nacos 和 seata server 的关系,看下图

tx-service-group 事物分组,在同一分布式事物中的服务,需要使用同一事物分组,事物分组如果不配置,默认是 spring.application.name + '-seata-service-group',这里笔者没有配置,使用默认的,即为 seata-at-account-learn-seata-service-group。事物分组是 seata的资源逻辑,事物分组详细说明,看官网文档截图

1.3、创建 order 服务

创建子工程 seata-at-order-learn 项目

seata-at-order-learn 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><artifactId>cloud-learn</artifactId><groupId>com.wsjzzcbq</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata-at-order-learn</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

启动类 SeataATOrderApplication

package com.wsjzzcbq;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;/*** SeataATOrderApplication** @author wsjz* @date 2023/10/14*/
@MapperScan(value = {"com.wsjzzcbq.mapper"})
@EnableFeignClients
@SpringBootApplication
public class SeataATOrderApplication {public static void main(String[] args) {SpringApplication.run(SeataATOrderApplication.class, args);}
}

订单实体类 Order

package com.wsjzzcbq.bean;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;/*** Order** @author wsjz* @date 2022/07/07*/
@TableName("order_tbl")
@Data
public class Order {private Integer id;private String userId;private String code;private Integer count;private Integer money;
}

OrderMapper

package com.wsjzzcbq.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wsjzzcbq.bean.Order;/*** OrderMapper** @author wsjz* @date 2022/07/07*/
public interface OrderMapper extends BaseMapper<Order> {
}

AccountFeign

package com.wsjzzcbq.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** AccountFeign** @author wsjz* @date 2023/10/13*/
@FeignClient(value = "seata-at-account-learn")
public interface AccountFeign {@RequestMapping("/account/reduce")String debit(@RequestParam("userId") String userId, @RequestParam("money") int money);
}

OrderService

package com.wsjzzcbq.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.wsjzzcbq.bean.Order;/*** OrderService** @author wsjz* @date 2022/07/07*/
public interface OrderService extends IService<Order> {void create(String userId, int money, boolean rollback);
}

OrderServiceImpl

package com.wsjzzcbq.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsjzzcbq.bean.Order;
import com.wsjzzcbq.feign.AccountFeign;
import com.wsjzzcbq.mapper.OrderMapper;
import com.wsjzzcbq.service.OrderService;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.UUID;/*** OrderServiceImpl** @author wsjz* @date 2022/07/07*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {@Autowiredprivate AccountFeign accountFeign;@GlobalTransactional@Overridepublic void create(String userId, int money, boolean rollback) {String xid = RootContext.getXID();System.out.println(xid);String orderCode = UUID.randomUUID().toString();Order order = new Order();order.setCode(orderCode);order.setCount(1);order.setUserId(userId);order.setMoney(money);this.save(order);accountFeign.debit(userId, money);if (rollback) {int a = 1/0;}}
}

OrderController

package com.wsjzzcbq.controller;import com.wsjzzcbq.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** OrderController** @author wsjz* @date 2022/07/09*/
@RequestMapping("/order")
@RestController
public class OrderController {@Autowiredprivate OrderService orderService;/*** http://localhost:9002/order/create?userId=101&money=10&rollback=false* @param userId* @param money* @param rollback* @return*/@RequestMapping("/create")public String create(String userId, int money, boolean rollback) {try {orderService.create(userId, money, rollback);return "下单成功";} catch (Exception e) {e.printStackTrace();return "下单失败";}}}

application.yml 文件

server:port: 9002
spring:application:name: seata-at-order-learndatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.3.232:3306/pmc-order?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456cloud:nacos:username: nacospassword: nacosserver-addr: 192.168.2.140discovery:namespace: public
#        server-addr: 192.168.2.140
#      config:
#        server-addr:seata:config:type: nacosnacos:server-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}group: SEATA_GROUPdata-id: seata.propertiesregistry:type: nacosnacos:application: seata-servercluster: defaultserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}group: SEATA_GROUP
# 事物分组,如果不配置默认是spring.application.name + '-seata-service-group'tx-service-group: seata-at-account-learn-seata-service-grouplogging:level:com.wsjzzcbq.mapper: debugmybatis-plus:global-config:db-config:id-type: auto

配置说明

基本和 account 服务配置相同,这里事物分组和 account 服务是一样的 seata-at-account-learn-seata-service-group

2、添加配置

2.1、客户端配置

需要在nacos 中新建 group 是 SEATA_GROUP,data-id 是 seata.properties 的客户端配置

配置内容如何获取?可以在github 上克隆seata 代码,在源代码 script 目录下有 config-center 目录,在 config-center 目录下有全部配置在 config.txt 文件中

seata 源代码地址:https://github.com/seata/seata

另一种方式是下载seata server,笔者下载的 seata server 1.7.1解压后,有 script目录,script目录下config-center 下config.txt 文件中有全部配置

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

config.txt 文件中有英文注释,说明了哪些配置是客户端的哪些是服务端的

这里笔者已经整理好了客户端配置,在nacos上新建 group 是 SEATA_GROUP,data-id 是 seata.properties 的配置,内容如下

seata.properties 内容

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none#Transaction routing rules configuration, only for the client
service.vgroupMapping.seata-at-account-learn-seata-service-group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h
# You can choose from the following options: fastjson, jackson, gson
tcc.contextJsonParserType=fastjson#Log rule configuration, for client and server
log.exceptionRate=100

这里需要改的有2处,一个是 service.vgroupMapping.seata-at-account-learn-seata-service-group=default,需要把 service.vgroupMapping. 后面的改成 account项目和 order 项目共同的事物分组 seata-at-account-learn-seata-service-group,这里笔者已经改完,默认的配置不是这个;另一处配置是 service.default.grouplist=127.0.0.1:8091,这里配置的是 seata server 的地址,因为笔者的 seata server 和项目在同一台电脑上,因此不做修改,使用127.0.0.1,读者可根据自己的情况配置

2.2、服务端配置

先下载 seata-server-1.7.1,然后进入 seata-server-1.7.1 的 conf 目录

在 application.yml 文件中进行配置

spring.application.name 默认是 seata-server ,和前面项目中配置的一样,不用修改

控制台账号密码默认都是 seata

seata config 和 registry 是关键,道理和客户端类似,seata server 从nacos 配置中心中获取group 是 SEATA_GROUP,data-id 是 seataServer.properties 的配置

同时会把自身以group 是 SEATA_GROUP,服务名是 seata-server 的形式注册到 nacos 注册中心

cluster 是 default,前面客户端的 service.vgroupMapping.seata-at-account-learn-seata-service-group=default,service.default.grouplist=127.0.0.1:8091,都是以 default 对应的

笔者的 seata-server-1.7.1 的 application.yml  配置内容

#  Copyright 1999-2019 Seata.io Group.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.server:port: 7091spring:application:name: seata-serverlogging:config: classpath:logback-spring.xmlfile:path: ${log.home:${user.home}/logs/seata}extend:logstash-appender:destination: 127.0.0.1:4560kafka-appender:bootstrap-servers: 127.0.0.1:9092topic: logback_to_logstashconsole:user:username: seatapassword: seata
seata:config:# support: nacos, consul, apollo, zk, etcd3type: nacosnacos:server-addr: 192.168.2.140:8848namespace:group: SEATA_GROUPusername: nacospassword: nacoscontext-path:##if use MSE Nacos with auth, mutex with username/password attribute#access-key:#secret-key:data-id: seataServer.properties    registry:# support: nacos, eureka, redis, zk, consul, etcd3, sofatype: nacosnacos:application: seata-serverserver-addr: 192.168.2.140:8848group: SEATA_GROUPnamespace:cluster: defaultusername: nacospassword: nacoscontext-path:##if use MSE Nacos with auth, mutex with username/password attribute#access-key:#secret-key:    #store:# support: file 、 db 、 redis#mode: file
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'security:secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017tokenValidityInMilliseconds: 1800000ignore:urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

配置完 seata-server-1.7.1 的 application.yml 文件后

在nacos 中新建配置 seataServer.properties 

seataServer.properties 内容

#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none#Log rule configuration, for client and server
log.exceptionRate=100#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
store.publicKey=#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.3.232:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
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#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.type=pipeline
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=true
server.enableParallelHandleBranch=false#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

这里的关键配置是存储 store,默认是 file 文件的形式

笔者使用 mysql 数据库 db的形式储存事物相关信息

需修改下面7项内容

store.mode=db
store.lock.mode=db
store.session.mode=db
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.3.232:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456

笔者使用 mysql8,因此使用 com.mysql.cj.jdbc.Driver,数据库信息读者根据自己的情况修改

nacos 中新建 seataServer.properties 

3、数据库建表

3.1、seata 服务端建表

笔者所有数据库使用同一数据库服务器

新建数据库 seata

建表 sql 在 seata-server-1.7.1 的 seata-server-1.7.1\seata\script\server\db 目录下

创建完成,有4张表

3.2、seata 客户端建表

seata 为实现分布式事物,业务库下需要有张记录日志的 undo_log 表

undo_log 表 sql 可以在seata源码 seata\script\client\at\db 目录下找到,不同版本 seata server 会有差异

笔者 account 服务建表,已包含 undo_log 表

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account`  (`id` int(0) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`money` int(0) NULL DEFAULT 0,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES (1, '101', 900);-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (`id` bigint(0) NOT NULL AUTO_INCREMENT,`branch_id` bigint(0) 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(0) 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;

笔者 order 服务建表,已包含 undo_log 表

DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl`  (`id` int(0) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`count` int(0) NULL DEFAULT 0,`money` int(0) NULL DEFAULT 0,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (`id` bigint(0) NOT NULL AUTO_INCREMENT,`branch_id` bigint(0) 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(0) 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;

建表完成

4、运行测试

启动 seata-server-1.7.1

进入 bin 目录,双击 seata-server.bat

seata 控制台:http://localhost:7091/

账号密码都是 seata

启动 account 和 order 服务

nacos 服务和配置

测试正常情况

浏览器请求:http://localhost:9002/order/create?userId=101&money=10&rollback=false

扣减账户 10 元,新增订单

测试回滚情况

5、Seata Server 1.4.2

seata-server-1.4.2 配置说明

进入 seata-server-1.4.2 的 conf 目录

配置文件是 registry.conf 和 file.conf,这个是seata 服务端早期的配置方式,没有1.7.1的application.yml 文件方便

registry.conf 文件中 registry, 通过 type 指定注册中心,默认是 file,如果使用 nacos,要在下面nacos 配置的位置配置nacos的信息,其他注册中心同理

registry.conf 文件中 config,通过 type 指定,默认是file,如果使用nacos,需要在下面nacos配置位置配置nacos信息,其他配置中心同理

file.conf 配置说明(如果registry.conf 文件中 config使用 file,file.conf 配置才生效),通过mode 指定存储形式,默认是file,如果想使用db,需要在下面db配置处配置数据库信息

6、项目代码

码云地址:https://gitee.com/wsjzzcbq/csdn-blog/tree/master/cloud-learn

至此完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode—2652.倍数求和【简单】

2023每日刷题&#xff08;四&#xff09; Leetcode—2652.倍数求和 实现代码 int sumOfMultiples(int n){int ans 0;int i 1;for(; i < n; i) {if((i % 3 0) || (i % 5 0) || (i % 7 0)) {ans i;}}return ans; }测试结果 之后我会持续更新&#xff0c;如果喜欢我的文…

STM32,我想看单片机上的外设时钟,我怎么看?

一&#xff1a;在工程中加入rcc文件 首先需要加载我们的时钟函数的文件 stm32f10x_rcc.h 和 stm32f10x_rcc.c 文件 二&#xff1a;查看文件 在h头文件 尾部&#xff0c;有我们这个总线的函数 在函数体内&#xff0c;有我们这个宏定义的 外设时钟&#xff0c;我们拿就行了 APB2_…

MapReduce编程:join操作和聚合操作

文章目录 MapReduce 编程&#xff1a;join操作和聚合操作一、实验目标二、实验要求及注意事项三、实验内容及步骤 附&#xff1a;系列文章 MapReduce 编程&#xff1a;join操作和聚合操作 一、实验目标 理解MapReduce计算框架的分布式处理工作流程掌握用mapreduce计算框架实现…

Git Bash(一)Windows下安装及使用

目录 一、简介1.1 什么是Git&#xff1f;1.2 Git 的主要特点1.3 什么是 Git Bash&#xff1f; 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置&#xff08;【Next】 即可&#xff09;3.4 安装完毕3.5 打开 Git Bash 官网地址&#xff1a; https://www.git-scm.com/…

codeforces (C++ Morning)

题目&#xff1a; 翻译&#xff1a; 思路&#xff1a; 1、要将四位数显示&#xff0c;每次操作可以选择移动光标&#xff08;移动到相邻的位置&#xff09;或者显示数字&#xff0c;计算最少需要多少次操作。 2、用flag表示当前光标位置&#xff0c;sum为记录操作次数&#…

开源软件-禅道Zentao

禅道Zentao 简介漏洞复现SQL注入漏洞**16.5****router.class.php SQL注入** **v18.0-v18.3****后台命令执行** 远程命令执行漏洞&#xff08;RCE&#xff09;后台命令执行 简介 是一款开源的项目管理软件&#xff0c;旨在帮助团队组织和管理他们的项目。Zentao提供了丰富的功能…

基于FPGA的图像拉普拉斯变换实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a vivado2019.2 3.部分核心程序 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 202…

【Java基础面试四十一】、说一说你对static关键字的理解

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说你对static关键字…

2525.根据规则将箱子分类/并查集/动态规划

2525. 根据规则将箱子分类 - 力扣&#xff08;LeetCode&#xff09; 给你四个整数 length &#xff0c;width &#xff0c;height 和 mass &#xff0c;分别表示一个箱子的三个维度和质量&#xff0c;请你返回一个表示箱子 类别 的字符串。 如果满足以下条件&#xff0c;那么…

《数据结构与算法之美》读书笔记1

Java的学习 方法参数多态&#xff08;向上和向下转型&#xff09; 向上转型&#xff1a; class Text{public static void main(String[] args) {Animals people1 new NiuMa();people1.eat1();//调用继承后公共部分的方法&#xff0c;没重写调用没重写的&#xff0c;重写了调…

基于Django与深度学习的股票预测系统 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 Django框架4 数据整理5 模型准备和训练6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于Django与深度学习的股票预测系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff…

Ubuntu桌面环境的切换方法

你在找它吗&#xff1f; 国内麒麟、深度等系统虽然界面更炫&#xff0c;但——软件仓库与Ubuntu官方已不兼容。国内系统遇到稳定性问题&#xff0c;还是得拿Ubuntu做参照。今天本来介绍下这款Linux桌面。 为什么在 Ubuntu 上考虑 LXQt&#xff1f; 性能&#xff1a;LXQt设计为…

计算机网络-计算机网络体系结构-传输层

目录 一、UDP 二、TCP 特点 首部格式 连接管理 可靠传输 流量控制(点对点) 拥塞控制(全局) 三、拥塞控制算法 慢开始&拥塞避免 快重传&快恢复 功能一&#xff1a;提供进程与进程之间的逻辑通信 功能二&#xff1a;复用和分用 功能三&#xff1a;对收到的报…

摩尔信使MThings的协议转换(数据网关)功能

摩尔信使MThings可以作为现场总线&#xff08;RS485&#xff09;和以太网的数据中枢&#xff0c;并拥有强大的Modbus协议转换功能。 数据网关功能提供协议转换和数据汇聚功能&#xff0c;可实现多维度映射&#xff0c;包括&#xff1a;不同的通道(总线)类型、协议类型&#xff…

PHP yield

概念&#xff1a; Generator&#xff1a;带 yield的function yield&#xff1a;Generator或task的中断关键字&#xff0c;执行到yield时一次调度周期执行完即阻塞&#xff0c;并返回右侧表达式结果&#xff0c;等待下一次调度器运行next()或迭代遍历才会继续往下执行&#xff0…

Axure RP静态站点的发布与内网穿透结合实现远程访问本地原型页面

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

python生成的报告中绘制了多张图,但最后都混合到一起了

问题来源&#xff1a; 用python生成的报告中&#xff0c;存在三张图&#xff0c;第一个张图是正常的&#xff0c; 后面的图都是不正常的&#xff0c;全都是多张图混合而成的&#xff0c;这是为什么呢&#xff1f; 三段代码均是下述调用方式 import matplotlib.pyplot as plt pl…

【Linux】操作系统的认识

操作系统 1. 冯诺依曼体系结构2. 操作系统 1. 冯诺依曼体系结构 冯诺依曼体系结构的介绍 冯.诺依曼结构消除了原始计算机体系中&#xff0c;只能依靠硬件控制程序的状况&#xff08;程序作为控制器的一部分&#xff0c;作为硬件存在&#xff09;&#xff0c;将程序编码存储在…

JUC并发编程笔记2

省流&#xff1a; 自己笔记&#xff0c;划走~~~~ 缓存更新策略

mybatis-plus自动填充

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 mybatis-plus自动填充 大家做设计数据表的时候&#xff0c;基本上都会有del_flag&#xff0c;create_time, update_time,这三个字段&#xff0c;这也是…