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.hqwc.cn/news/144663.html

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

相关文章

Java利用反射和读取xml实现迷你容器

由于需要框架能实现多态&#xff0c;达到控制反转解耦。所以容器还是需要的&#xff0c;容器的存在可以简化对象获取工作&#xff0c;但是容器也不是万能的。合理使用即可&#xff0c;Spring对我来说太庞大了&#xff0c;用不着&#xff0c;为此给框架写一个迷你版容器。 容器…

SpringCloud-Sentinel

一、介绍 &#xff08;1&#xff09;提供界面配置配置服务限流、服务降级、服务熔断 &#xff08;2&#xff09;SentinelResource的blockHandler只处理后台配置的异常&#xff0c;运行时异常fallBack处理&#xff0c;且资源名为value时才生效&#xff0c;走兜底方法 二、安装…

裸机与RTOS(概念、关系、区别)

目录 裸机 什么是裸机&#xff1f; 裸机开发的特点 STM32裸机开发 RTOS 什么是RTOS&#xff1f; RTOS技术的概念及特点 STM32中的RTOS 裸机开发与RTOS开发对比分析 裸机开发 RTOS开发 如何选择&#xff1f; 裸机 什么是裸机&#xff1f; 在嵌入式领域&#xff0c;…

UE5--物体卡片与材质入门

参考资料&#xff1a; 《Unreal Engine5 入门到精通》--左央 虚幻引擎5.2文档&#xff1a;https://docs.unrealengine.com/5.2/zh-CN/ 前言&#xff1a; 跟着左央老师的《Unreal Engine5 入门到精通》学习制作AI版胡闹厨房&#xff0c;把学习过程与学习到的东西归纳总结起来。 …

通用FIFO设计深度8宽度64,verilog仿真,源码和视频

名称&#xff1a;通用FIFO设计深度8宽度64&#xff0c;verilog仿真 软件&#xff1a;Quartus 语言&#xff1a;verilog 本代码为FIFO通用代码&#xff0c;其他深度和位宽可简单修改以下参数得到 reg [63:0] ram [7:0];//RAM。深度8&#xff0c;宽度64 代码功能&#xff1a…

存储优化知识复习二详细版解析

存储优化 知识复习二 一、 选择题 1、 对数据库调优的方法中&#xff0c;最困难但是最有成效的是( )。 A、优化表的架构设计 B、添加内存 C、索引优化 D、查询语句优化 【参考答案】A2、 防止与处理死锁的方法有&#xff08; &#xff09;。 A、尽量避免或尽快处理阻塞 B、访…

人工智能、机器学习、深度学习的区别

人工智能涵盖范围最广&#xff0c;它包含了机器学习&#xff1b;而机器学习是人工智能的重要研究内容&#xff0c;它又包含了深度学习。 人工智能&#xff08;AI&#xff09; 人工智能是一门以计算机科学为基础&#xff0c;融合了数学、神经学、心理学、控制学等多个科目的交…

【项目设计】网络对战五子棋(上)

想回家过年… 文章目录 一、项目前置知识1. websocketpp库1.1 http1.0/1.1和websocket协议1.2 websocketpp库接口的前置认识1.3 搭建一个http/websocket服务器 2. jsoncpp库3. mysqlclient库 二、 项目设计1. 项目模块划分2. 实用工具类模块2.1 日志宏封装2.2 mysql_util2.3 j…

1、VMware虚拟机及网络配置

一、VMware虚拟网络编辑器 1、选择NAT模式并配置子网 2、进入NAT设置&#xff0c;配置网关 3、宿主机网络适配器设置 二、创建虚拟机 在这里插入图片描述 三、开启虚拟机&#xff0c;安装操作系统 在该网段内配置静态ip&#xff0c;指定网关为前面NAT配置的网关地址…

微信小程序之个人中心授权登录

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.了解微信授权登录 微信登录官网&#xff1a; 小程序登录https://developers.weixin.qq.com/miniprogram/d…

【面试经典150 | 栈】有效的括号

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;栈哈希表 其他语言cpython3 写在最后 Tag 【栈】 题目来源 20. 有效的括号 题目解读 括号有三种类型&#xff0c;分别是小括号、中括号和大括号&#xff0c;每种括号的左右两半括号必须一一对应才是有效的括号&#…

好用的办公软件有哪些

日常的工作难免和各种各样的软件打交道&#xff0c;除了传统的Office三件套&#xff0c;小编日常还在用着其他的办公软件&#xff0c;借此跟各位分享其中比较好用、堪称办公神器的8款软件&#xff01; 1.WPS office 2.office2007 3.EasyConnect 4.ToDesk 5.Photoshop 6.A…