文章目录
【Spring Cloud Alibaba】Seata 分布式事务
1、Spring Cloud Alibaba Seata
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳的度过历年的双 11,对各 BU 业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019.1 为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备
Seata 的官网,https://seata.io/zh-cn/
Spring Cloud 快速集成 Seata,https://github.com/seata/seata-samples/blob/master/doc/quick-integration-with-spring-cloud.md
本篇文章使用的是 Seata 的 AT 模式
业务需求:下订单 -> 减库存 -> 扣余额 -> 改订单状态
源码中的模块名称变更了,之前大意多了一个 boot,这里修改了一下
变更前 | 变更后 |
---|---|
spring-cloud-alibaba-boot-seata-account | spring-cloud-alibaba-seata-account |
spring-cloud-alibaba-boot-seata-order | spring-cloud-alibaba-seata-order |
spring-cloud-alibaba-boot-seata-storage | spring-cloud-alibaba-seata-storage |
2、服务公共内容
公共内容需要在每个模块中都添加,除了 application.yml 有一点区别,其他所有配置相同
(1)相关依赖
三个模块的依赖相同
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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>
<version>${spring-cloud-starter-openfeign.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>${swagger-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
(2)application.yml
三个服务需要分别修改端口,数据库名字,其他的 application.yml 配置文件都一样
模块 | 端口 | 端点 | 数据库 |
---|---|---|---|
spring-cloud-alibaba-boot-seata-account | 8007 | 9007 | alibaba-seata-account |
spring-cloud-alibaba-boot-seata-order | 8008 | 9008 | alibaba-seata-order |
spring-cloud-alibaba-boot-seata-storage | 8009 | 9009 | alibaba-seata-storage |
# 应用配置
server:
port: 8007
# 端点监控
management:
endpoint:
health:
show-details: always
endpoints:
jmx:
exposure:
include: '*'
web:
exposure:
include: '*'
server:
port: 9007
spring:
# 应用名称
application:
name: spring-cloud-alibaba-boot-seata-account
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/alibaba-seata-account?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
write-dates-as-timestamps: false
# 微服务配置
cloud:
# Nacos配置
nacos:
discovery:
namespace: sandbox-configuration
password: nacos
server-addr: localhost:8848
username: nacos
alibaba:
# Seata配置
seata:
tx-service-group: tellsea_tx_group
# MybatisPlus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:mapper/**/*Mapper.xml
(3)file.conf、registry.conf
在你下载的 seata 的 bin,目录中复制到项目的 resource 目录下
并在 file.conf 文件中增加,与 store 同级,因为默认配置文件中没有
service {
#vgroup->rgroup
vgroupMapping.tellsea_tx_group = "default"
#only support single node
default.grouplist = "127.0.0.1:8091"
#degrade current not support
enableDegrade = false
#disable
disable = false
#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
max.commit.retry.timeout = "-1"
max.rollback.retry.timeout = "-1"
}
(4)AjaxResult
三个服务的 AjaxResult 相同
package cn.tellsea.entity;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import java.util.HashMap;
/**
* 公共返回值
*
* @author Tellsea
* @date 2021/12/31
*/
public class AjaxResult<T> extends HashMap<String, Object> {
/**
* 状态码
*/
public static final String CODE_TAG = "code";
/**
* 返回内容
*/
public static final String MSG_TAG = "msg";
/**
* 数据对象
*/
public static final String DATA_TAG = "data";
private static final long serialVersionUID = 1L;
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult() {
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, T data) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (!ObjectUtils.isEmpty(data)) {
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult<Void> success() {
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static <T> AjaxResult<T> success(T data) {
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult<Void> success(String msg) {
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static <T> AjaxResult<T> success(String msg, T data) {
return new AjaxResult(HttpStatus.OK.value(), msg, data);
}
/**
* 返回错误消息
*
* @return
*/
public static AjaxResult<Void> error() {
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult<Void> error(String msg) {
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static <T> AjaxResult<T> error(String msg, T data) {
return new AjaxResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult<Void> error(int code, String msg) {
return new AjaxResult(code, msg, null);
}
public Integer getCode() {
return (Integer) super.get(CODE_TAG);
}
public String getMsg() {
return (String) super.get(MSG_TAG);
}
public T getData() {
return (T) super.get(DATA_TAG);
}
}
(5)代码生成
使用代码生成器,分别生成 controller、service、serviceImpl、mapper、mapper.xml 文件,不会使用的看上一篇文章
【Spring Cloud Alibaba】Mybatis Plus 代码生成器:https://mp.weixin.qq.com/s/9OZRbIqhLEOhH3QKEJWwPg
有不懂的地方,可以微信公众号留言,项目源码在:https://gitee.com/tellsea/spring-cloud-alibaba-learn
(6)创建模块数据库
3、搭建账户服务
创建 spring-cloud-alibaba-boot-seata-account 模块,先把第二节的账户服务都操作完成
控制层
package cn.tellsea.controller;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.service.IBizAccountService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
/**
* <p>
* 账户表 前端控制器
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@RestController
@RequestMapping("/bizAccount")
public class BizAccountController {
@Autowired
private IBizAccountService accountService;
@ApiOperation("扣减账户")
@PostMapping("/account/decrease")
AjaxResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money) {
return accountService.decrease(userId, money);
}
}
接口层
package cn.tellsea.service;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizAccount;
import com.baomidou.mybatisplus.extension.service.IService;
import java.math.BigDecimal;
/**
* <p>
* 账户表 服务类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
public interface IBizAccountService extends IService<BizAccount> {
/**
* 扣减账户
*
* @param userId
* @param money
* @return
*/
AjaxResult decrease(Long userId, BigDecimal money);
}
接口实现层
package cn.tellsea.service.impl;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizAccount;
import cn.tellsea.mapper.BizAccountMapper;
import cn.tellsea.service.IBizAccountService;
import cn.tellsea.utils.BigDecimalUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* <p>
* 账户表 服务实现类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@Slf4j
@Service
public class BizAccountServiceImpl extends ServiceImpl<BizAccountMapper, BizAccount> implements IBizAccountService {
@Override
public AjaxResult decrease(Long userId, BigDecimal money) {
log.info("------->扣减余额开始");
//模拟超时异常,全局事务回滚
//暂停几秒钟线程
//try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
BizAccount account = baseMapper.selectById(userId);
account.setResidue(BigDecimalUtils.subtract(account.getResidue(), money));
account.setUsed(BigDecimalUtils.add(account.getUsed(), money));
baseMapper.updateById(account);
log.info("------->扣减余额结束");
return AjaxResult.success("扣减余额成功");
}
}
账户模块需要增加一个 BigDecimalUtils 工具类
package cn.tellsea.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 金额计算工具类
*
* @author Tellsea
* @date 2021/12/31
*/
public class BigDecimalUtils {
/**
* 默认保存2位小数点
*/
private static int POINTS = 2;
/**
* 默认进位方式
*/
private static RoundingMode MODE = RoundingMode.CEILING;
/**
* 加
*
* @param a
* @param b
* @return
*/
public static BigDecimal add(BigDecimal a, BigDecimal b) {
if (a == null) {
a = BigDecimal.valueOf(0.00);
}
if (b == null) {
b = BigDecimal.valueOf(0.00);
}
return computer(1, a, b, POINTS, MODE);
}
public static BigDecimal add(BigDecimal a, BigDecimal b, int points, RoundingMode mode) {
if (a == null) {
a = BigDecimal.valueOf(0.00);
}
if (b == null) {
b = BigDecimal.valueOf(0.00);
}
return computer(1, a, b, points, mode);
}
/**
* 减
*
* @param a
* @param b
* @return
*/
public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
if (a == null) {
a = BigDecimal.valueOf(0.00);
}
if (b == null) {
b = BigDecimal.valueOf(0.00);
}
return computer(2, a, b, POINTS, MODE);
}
public static BigDecimal subtract(BigDecimal a, BigDecimal b, int points, RoundingMode mode) {
if (a == null) {
a = BigDecimal.valueOf(0.00);
}
if (b == null) {
b = BigDecimal.valueOf(0.00);
}
return computer(2, a, b, points, mode);
}
/**
* 乘
*
* @param a
* @param b
* @return
*/
public static BigDecimal multiply(BigDecimal a, BigDecimal b) {
return computer(3, a, b, POINTS, MODE);
}
/**
* 除
*
* @param a
* @param b
* @return
*/
public static BigDecimal divide(BigDecimal a, BigDecimal b) {
if (b.compareTo(BigDecimal.ZERO) == 0) {
return BigDecimal.valueOf(0.00);
}
return computer(4, a, b, POINTS, MODE);
}
public static BigDecimal divide(BigDecimal a, BigDecimal b, int points, RoundingMode mode) {
return computer(4, a, b, points, mode);
}
/**
* 计算方法
*
* @param type 1-加 2-减 3-乘 4-除
* @param a
* @param b
* @param points
* @param mode
* @return
*/
public static BigDecimal computer(int type, BigDecimal a, BigDecimal b, int points, RoundingMode mode) {
BigDecimal rs;
switch (type) {
case 1:
rs = a.add(b).setScale(points, mode);
break;
case 2:
rs = a.subtract(b).setScale(points, mode);
break;
case 3:
rs = a.multiply(b).setScale(points, mode);
break;
default:
rs = a.divide(b, points, mode);
break;
}
return rs;
}
public BigDecimal multiply(BigDecimal a, BigDecimal b, int points, RoundingMode mode) {
return computer(3, a, b, points, mode);
}
}
启动类增加注解
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("cn.tellsea.mapper")
4、搭建订单服务
创建 spring-cloud-alibaba-boot-seata-order 模块,先把第二节的账户服务都操作完成
控制层
package cn.tellsea.controller;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizOrder;
import cn.tellsea.service.IBizOrderService;
import io.swagger.annotations.ApiOperation;
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;
/**
* <p>
* 订单表 前端控制器
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@RestController
@RequestMapping("/bizOrder")
public class BizOrderController {
@Autowired
private IBizOrderService orderService;
@ApiOperation("创建订单")
@GetMapping("/createOrder")
public AjaxResult createOrder(BizOrder entity) {
return orderService.createOrder(entity);
}
}
接口层
package cn.tellsea.service;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizOrder;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 订单表 服务类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
public interface IBizOrderService extends IService<BizOrder> {
/**
* 创建订单
*
* @param entity
* @return
*/
AjaxResult createOrder(BizOrder entity);
}
接口实现层
package cn.tellsea.service.impl;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizOrder;
import cn.tellsea.feignclient.FeignBizAccountService;
import cn.tellsea.feignclient.FeignBizStorageService;
import cn.tellsea.mapper.BizOrderMapper;
import cn.tellsea.service.IBizOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <p>
* 订单表 服务实现类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@Slf4j
@Service
public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> implements IBizOrderService {
@Autowired
private FeignBizAccountService accountService;
@Autowired
private FeignBizStorageService storageService;
@Override
public AjaxResult createOrder(BizOrder entity) {
log.info("------>开始新建订单");
baseMapper.insert(entity);
log.info("------>订单微服务开始调用库存,扣减count");
storageService.decrease(entity.getProductId(), entity.getCount());
log.info("------>订单微服务开始调用库存,扣减end");
log.info("------>订单微服务开始调用账户,扣减money");
accountService.decrease(entity.getUserId(), entity.getMoney());
log.info("------>订单微服务开始调用账户,扣减end");
log.info("------>开始修改订单状态");
entity.setStatus(2);
baseMapper.updateById(entity);
log.info("------>修改订单状态完毕");
log.info("------>下单完毕");
return AjaxResult.success("下单成功");
}
}
启动类增加注解
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("cn.tellsea.mapper")
增加账户服务远程调用接口
package cn.tellsea.feignclient;
import cn.tellsea.entity.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.math.BigDecimal;
/**
* 账户服务
*
* @author Tellsea
* @date 2021/12/31
*/
@FeignClient("spring-cloud-alibaba-boot-seata-account")
public interface FeignBizAccountService {
/**
* 扣减账户余额
*
* @param userId
* @param money
* @return
*/
@PostMapping("/bizAccount/account/decrease")
AjaxResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}
增加库存服务远程调用接口
package cn.tellsea.feignclient;
import cn.tellsea.entity.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 库存服务
*
* @author Tellsea
* @date 2021/12/31
*/
@FeignClient(value = "spring-cloud-alibaba-boot-seata-storage")
public interface FeignBizStorageService {
/**
* 扣减库存
*
* @param productId
* @param count
* @return
*/
@PostMapping("/bizStorage/storage/decrease")
AjaxResult decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}
5、搭建库存服务
创建 spring-cloud-alibaba-boot-seata-storage 模块,先把第二节的账户服务都操作完成
控制层
package cn.tellsea.controller;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.service.IBizStorageService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 库存表 前端控制器
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@RestController
@RequestMapping("/bizStorage")
public class BizStorageController {
@Autowired
private IBizStorageService storageService;
@ApiOperation("扣减库存")
@RequestMapping("/storage/decrease")
public AjaxResult decrease(Long productId, Integer count) {
return storageService.decrease(productId, count);
}
}
接口层
package cn.tellsea.service;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizStorage;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 库存表 服务类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
public interface IBizStorageService extends IService<BizStorage> {
/**
* 扣减库存
*
* @param productId
* @param count
* @return
*/
AjaxResult decrease(Long productId, Integer count);
}
接口实现层
package cn.tellsea.service.impl;
import cn.tellsea.entity.AjaxResult;
import cn.tellsea.entity.BizStorage;
import cn.tellsea.mapper.BizStorageMapper;
import cn.tellsea.service.IBizStorageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* <p>
* 库存表 服务实现类
* </p>
*
* @author Tellsea
* @since 2021-12-31
*/
@Slf4j
@Service
public class BizStorageServiceImpl extends ServiceImpl<BizStorageMapper, BizStorage> implements IBizStorageService {
@Override
public AjaxResult decrease(Long productId, Integer count) {
log.info("------->中扣减库存开始");
BizStorage storage = baseMapper.selectById(productId);
storage.setUsed(storage.getUsed() + count);
storage.setResidue(storage.getResidue() - count);
baseMapper.updateById(storage);
log.info("------->中扣减库存结束");
return AjaxResult.success("扣减库存成功");
}
}
启动类增加注解
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("cn.tellsea.mapper")
6、测试下单业务
业务需求:下订单 -> 减库存 -> 扣余额 -> 改订单状态
(1)检查服务启动结果
启动三个 服务
检查 Nacos 的服务注册
(2)正常情况下单
数据库请求之前的数据
账户
订单
库存
访问线面连接下单
http://localhost:8008/bizOrder/createOrder?userId=1&productId=1&count=10&money=100
返回结果下单成功
账户:扣减
订单:创建完成
库存:扣减
(3)出错情况下单
在 spring-cloud-alibaba-boot-seata-account 模块的扣减账户余额中增加线程休眠
@Override
public AjaxResult decrease(Long userId, BigDecimal money) {
log.info("------->扣减余额开始");
//模拟超时异常,全局事务回滚
//暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
BizAccount account = baseMapper.selectById(userId);
account.setResidue(BigDecimalUtils.subtract(account.getResidue(), money));
account.setUsed(BigDecimalUtils.add(account.getUsed(), money));
baseMapper.updateById(account);
log.info("------->扣减余额结束");
return AjaxResult.success("扣减余额成功");
}
重新访问下单连接
http://localhost:8008/bizOrder/createOrder?userId=1&productId=1&count=10&money=100
报错,因为 OpenFeign 默认调用时限为 1 秒
账户:余额不变
订单:已创建,但未完成
检查商品库存,丢失了!!!
(4)增加 Seata 事物
在创建订单的接口上增加全局事物注解
@GlobalTransactional(name = "tellsea_tx_group", rollbackFor = Exception.class)
重启服务
再次调用
http://localhost:8008/bizOrder/createOrder?userId=1&productId=1&count=10&money=100
同样的报错
账户:未变动
订单:未变动
库存:未变动
到此,Spring Cloud Alibaba Seata 分布式事物,控制成功
7、常见报错
(1)endpoint format should like ip:port
启动服务时,发现报错
2021-03-02 16:22:09.693 ERROR 8384 --- [ main] i.s.c.r.netty.NettyClientChannelManager : Failed to get available servers: endpoint format should like ip:port
java.lang.IllegalArgumentException: endpoint format should like ip:port
at io.seata.discovery.registry.FileRegistryServiceImpl.lookup(FileRegistryServiceImpl.java:95) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.NettyClientChannelManager.getAvailServerList(NettyClientChannelManager.java:217) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.NettyClientChannelManager.reconnect(NettyClientChannelManager.java:162) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.RmNettyRemotingClient.registerResource(RmNettyRemotingClient.java:181) [seata-all-1.3.0.jar:1.3.0]
at io.seata.rm.AbstractResourceManager.registerResource(AbstractResourceManager.java:121) [seata-all-1.3.0.jar:1.3.0]
at io.seata.rm.datasource.DataSourceManager.registerResource(DataSourceManager.java:146) [seata-all-1.3.0.jar:1.3.0]
at io.seata.rm.DefaultResourceManager.registerResource(DefaultResourceManager.java:114) [seata-all-1.3.0.jar:1.3.0]
本文使用的 seata 依赖是 spring cloud alibaba seata,所以配置信息应该在 alibaba 下
- tellsea_tx_group:自定义的组名称,与 vgroupMapping. 的点之后的名称对应
- seata 版本的不同,vgroupMapping 可能是 vgroup-mapping,这个直接看源码就知道了
错误版本
spring:
cloud:
# Seata配置
seata:
tx-service-group: tellsea_tx_group
正确版本
spring:
cloud:
alibaba:
# Seata配置
seata:
tx-service-group: tellsea_tx_group