springBoot集成seata
前置条件:安装nacos和mysql数据库
⼀⼂下载seata服务端安装包,将下载的安装包上传⾄Linux并解压
1.2-1.4版本都可以
[root@iZuf6f6me43woqf6q431tqZ mysoft]# ls
docker-compose jdk1.8.0_212 maven-3.6.3 mysql-8.0.23 nginx-1.20.1 node redis-6.2.1 seata seata-server-1.2. tomcat-9.0.45
[root@iZuf6f6me43woqf6q431tqZ mysoft]#
⼆⼂进⼊解压后的seata/conf⽬录,编辑f⽂件内容如下,即将type设为nacos,并填写⾃⼰的nacos配置信息,表⽰将seata服务端注册到nacos中
备注:application,cluster,group的值建议和我填⼀样,不然客户端启动时可能会不到服务
type = "nacos"
nacos {
application = "serverAddr"
serverAddr = "127.0.0.1:8848"
namespace = "aa94072f-3269-409c-a065-ed0910a03f45"
cluster = "default"
group = "DEFAULT_GROUP"
}
三⼂到seata/bin⽬录下启动seata
后台启动:nohup ./seata-server.sh -h 127.0.0.1 -p 8091 >log.out 2>1 & 指定ip
备注:(1)这⾥最好将127.0.0.1换成你的Linux外⽹地址,不然客户端启动时可能会不到服务,(2)如果启动时报内存不⾜等错误,可以编辑seata-server.sh⽂件,将2048改成256
若启动没有异常,打开nacos,查看seta服务是否已经注册到nacos中
四⼂新建⼀个微服务⼯程,并编写⼀个可能存在分布式事务的服务调⽤⽅法,例如,我这⾥有订单,账户,库存,三个微服务
其中⽤户下单时,会先创建订单,然后扣减账户余额,最后扣减库存。我们在扣减账户余额的时候抛出异常,观察订单表中的数据是否会回滚,若回滚,则说明分布式事务⽣效了。
order服务的调⽤代码
@Override
public void createOrder(OrderEntity orderEntity) {
LOGGER.info("------->下单开始");
//创建订单
this.save(orderEntity);
//扣减账户余额
accountServer.UserId(),Money());
//扣减库存
storageServer.ProductId(),Count());
LOGGER.info("------->下单结束");
}
account服务代码
@Override
public void decreaseAccount(Long userId, BigDecimal money) {
LOGGER.info("------->account-service中扣减账户余额开始");
AccountEntity accountEntity = this.baseMapper.selectList(Wrappers.<AccountEntity>lambdaQuery().eq(AccountEntity::getUserId, userId)).get(0);
//异常,全局事务回滚
if (Residue()pareTo(money) < 0)
throw new RuntimeException("余额不⾜");
accountEntity.Residue().subtract(money));
accountEntity.Used().add(money));
this.updateById(accountEntity);
LOGGER.info("------->account-service中扣减账户余额结束");
}
五⼂在每⼀个服务中都引⼊seata客户端依赖,因为这⾥与spring-boot集成,所以选择seata-spring-boot-starter,这⾥客户端版本选择最新的1.3.0
<!--seata 分布式事务-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
六⼂在每⼀个微服务的配置⽂件中加⼊如下seata配置信息
备注:把enable-auto-data-source-proxy置为false(取消⾃动代理数据源)
# seata配置
seata:
enabled: true
enable-auto-data-source-proxy: false
application-id: ${spring.application.name}
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
registry:
type: nacos
nacos:
application: serverAddr
server-addr: 127.0.0.1:8848
namespace: aa94072f-3269-409c-a065-ed0910a03f45
group: DEFAULT_GROUP
cluster: default
config:
file:
name: f
七⼂在每⼀个微服务下编写如下配置类,并在每⼀个微服务的启动类上排除默认的数据源
@Configuration
public class DataSourceProxyConfig {
@Autowired
private DataSourceConfig dataSourceConfig;微服务在哪里
@Bean("dataSource")
public DataSource druidDataSource() {
HikariDataSource hikariDataSource = new HikariDataSource ();
hikariDataSource.Username());
hikariDataSource.Password());
hikariDataSource.Url());
hikariDataSource.DriveClassName());
return hikariDataSource;
}
@Bean
@Primary
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
}
DataSourceConfig 信息
@Data
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driveClassName;
}
排除默认的数据源:在每⼀个微服务的启动类上加上@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
备注:如果你也引⼊mybatis-plus依赖,则代理数据源的⽅式最后和我保持⼀致,否则以其他⽅式代理数据源,可能会导致mybatis-plus的某些功能失效。
⼋⼂最后在开始微服务调⽤的⽅法上加上@GlobalTransactional(rollbackFor = Exception.class)
启动每⼀个微服务,若出现如下信息,则说明每⼀个seata客户端都注册到了seata服务端中
2021-11-06 15:04:28.042 INFO 14524 --- [eoutChecker_1_1] NettyClientChannelManager : will connect to 127.0.0.1:8091
2021-11-06 15:04:28.043 INFO 14524 --- [eoutChecker_1_1] pcty.NettyPoolableFactory : NettyPool create channel to transactionRole:TMROLE,address:127.0.0.1:8091,msg:< RegisterTMRequest{applicationId='storage',
transaction 2021-11-06 15:04:28.132 INFO 14524 --- [eoutChecker_1_1] pcty.TmNettyRemotingClient : register TM success. client version:1.3.0, server version:1.2.0,channel:[id: 0x878eb8e6, L:/192.168.0.101:54031 - R:/127.0.0.1:8091]
2021-11-06 15:04:28.132 INFO 14524 --- [eoutChecker_1_1] pcty.NettyPoolableFactory : register success, cost 34 ms, version:1.2.0,role:TMROLE,channel:[id: 0x878eb8e6, L:/192.168.0.101:54031 - R:/47.100.205.138:8091] 九⼂访问order服务中创建订单的接⼝,观察事务是否回滚,若order服务下出现如下信息,则说明全局事务⽣效了
2021-11-06 15:18:07.776 INFO 24452 --- [h_RMROLE_1_1_16] d.undo.AbstractUndoLogManager : xid 127.0.0.1:8091:2026427667 branch 2026427668, undo_log deleted with GlobalFinished
2021-11-06 15:18:07.793 INFO 24452 --- [h_RMROLE_1_1_16] AbstractRMHandler : Branch Rollbacked result: PhaseTwo_Rollbacked
2021-11-06 15:18:07.817 INFO 24452 --- [nio-8088-exec-7] api.DefaultGlobalTransaction : [127.0.0.1:8091:2026427667] rollback status: Rollbacked
2021-11-06 15:18:07.831 ERROR 24452 --- [nio-8088-exec-7] C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/orderServer] threw exception [Request processing failed; nested exception i
⼗⼂结语:seata集成当你最后完成时看似简单,但整个过程确实很艰难,耗时费⼒,在集成过程中总是会出现各种错误,如seata server启动报错,客户端启动不到服务,全
局事务不会滚,mybatis-plus失效,代理数据源不⽣效等等,基本上⽹上哪些seata集成的各种错误我都遇到了,不得不说seata的整合的确很不友好,没有极⼤的耐⼼很难坚持下
来。上⾯的步骤,也只是我对最终效果的总结,可能并不适合每⼀个⼈。⼤家还是遇到报错时还是具体问题具体分析。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论