Alibaba seata 分布式事务介绍及配置使用

 2023-09-15 阅读 19 评论 0

摘要:一、介绍 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 相关术语: TC (Transaction Coordinator) - 事务协调者。维护全

一、介绍

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

相关术语:

TC (Transaction Coordinator) - 事务协调者。维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器。定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器。管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

本章我们将做一个简单的通过seata 实现微服务调用的异常发生后,事务控制内的远程服务数据回滚。

环境:nacos-server-1.2.1、seata-server-0.9.0

二、服务端搭建

1,下载压缩包,解压

首先下载  seata-server-0.9.0.zip 压缩文件,并进行解压。下载地址:http://seata.io/zh-cn/blog/download.html

2,修改file.conf 配置文件

修改 seata-server-0.9.0\seata\conf\file.conf 需要修改两处,修改service 下的 vgroup_mapping.my_test_tx_group 值,表示事物分组名称,唯一即可。

修改,事务日志的存储模式为 数据库模式,以及数据库链接信息。数据库信息下一部分介绍。

修改 服务注册文件配置seata-server-0.9.0\seata\conf\registry.conf ,我们将注册中心类型修改为nacos,并修改nacos的注册中心地址。

3,启动nacos和seata

登录nacos 可以看到 seata 服务端已经注册到 nacos中,服务端搭建完成。

三、数据库环境搭建

在 seata的解压文件中有两个数据库脚本,db_store.sql 为我们上一步中file.conf 中配置的数据库链接的数据库脚本。我们需要创建一个数据库,并将该脚本导入执行,执行完毕后将会创建三张数据库表。如下图:

db_undo_log.sql 脚本为我们每个微服务中需要进行数据库事务控制的应用中需要创建的业务表,在我们的每个业务数据库中进行创建。创建成功后也将会出现一张表。如下图:

四、生产者工程客户端搭建

客户端工程本次我们将搭建两个工程,一个生产者工程进行数据库操作,一个消费者工程进行远程调用。

父工程pom依赖链接:SpringCloud系列博客父工程xml依赖

生产者工程 seata_product_service项目结构如下:

seata_product_service 工程搭建如下:

1,pom 引入nacos和 seata 添加依赖,seata 版本需要与我们服务端版本一致。

<!-- SpringCloud Alibaba nacos -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- seata -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><exclusion><artifactId>seata-all</artifactId><groupId>io.seata</groupId></exclusion></exclusions>
</dependency>
<dependency><groupId>io.seata</groupId><artifactId>seata-all</artifactId><version>0.9.0</version>
</dependency>

2,创建配置文件

application.yml 如下,需要注意的是 spring.cloud.alibaba.seata.tx-service-group 项 值为我们的第二大部中 file.conf 文件中修改的vgroup_mapping.my_test_tx_group项 值一致。

server:port: 8001 #服务端口spring:application:name: cloud-payment-service #服务名称cloud:alibaba:seata:tx-service-group: xiaohui_tx_groupnacos:discovery:server-addr: 127.0.0.1:8848datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: org.gjt.mm.mysql.Driverurl: jdbc:mysql://127.0.0.1:3306/springcloud?useUnicode=true&characterEncoding=utf8&useSSL=trueusername: rootpassword: root#添加日志级别可以控制台打印节点上的链路信息
logging:level:root: INFOmanagement:endpoints:web:exposure:include: '*'
mybatis:mapperLocations: classpath:mapper/*.xmltype-aliases-package: com.xiaohui.springcloud.entities

与配置文件 application.yml 同级的 file.conf 和 registry.conf 都为从服务端调整后的文件复制过来,注意的是 file.conf 需要修改

 vgroup_mapping.my_test_tx_group = "xiaohui_tx_group" 为如下形式,否则 在客户端启动后会出现 no available service 'null' found, please make sure registry config correct 异常,导致服务无法调用。

3,调整数据库DataSourceProxy 数据源代理对象为seata的代理对象。

com.xiaohui.springcloud.config.DataSourceProxyConfig

package com.xiaohui.springcloud.config;import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;@Configuration
public class DataSourceProxyConfig {@Value("${mybatis.mapperLocations}")private String mapperLocations;@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource(){return new DruidDataSource();}@Beanpublic DataSourceProxy dataSourceProxy(DataSource dataSource){return new DataSourceProxy(dataSource);}@Beanpublic SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception{SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSourceProxy);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());return sqlSessionFactoryBean.getObject();}}

com.xiaohui.springcloud.config.MyBatisConfig

package com.xiaohui.springcloud.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan({"com.xiaohui.springcloud.dao"})
public class MyBatisConfig {
}

4,主启动类,需要排除SpringBoot的数据源自动配置。

package com.xiaohui.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class,args);}
}

5,业务类

其他代码参考文章:《SpringCloud(二) 生产者、消费者工程搭建与调用(上)》

@RestController
@Slf4j
public class PaymentController {@AutowiredIPaymentService paymentService;@PostMapping("/payment/create")public CommonResult insert(@RequestBody Payment payment){int id = paymentService.insert(payment);if(id > 0){return new CommonResult(0,"插入成功",id);}else{return new CommonResult(-9999,"插入失败",id);}}
}

五、消费者端工程搭建

父工程pom依赖链接:SpringCloud系列博客父工程xml依赖

消费者工程 seata_feign_order_service项目结构如下:

1,pom.xml  主要依赖 nacos seata openfeign

<!-- SpringCloud Alibaba nacos -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- seata -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><exclusion><artifactId>seata-all</artifactId><groupId>io.seata</groupId></exclusion></exclusions>
</dependency>
<dependency><groupId>io.seata</groupId><artifactId>seata-all</artifactId><version>0.9.0</version>
</dependency><!-- springCloud 整合的openFeign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2,配置文件

application.yml 如下:

server:port: 9001spring:application:name: openfeign-order-servicecloud:nacos:discovery:server-addr: 127.0.0.1:8848alibaba:seata:tx-service-group: xiaohui_tx_groupfeign:#开启对hystrix 支持,默认falsehystrix:enabled: falselogging:level:com.xiaohui.springcloud.service.ProductFeignClient: debug#actuator配置暴露的端点 * 表示全部。 还有 info、health、beans等
management:endpoints:web:exposure:include: '*'

file.comf 和 registry.conf 与生产者工程中文件一致。

3,主启动类(exclude 可不要,当该应用存在数据库操作时,则需要和生产者工程一样,需要添加排除自动加载数据源,以及配置seata的数据源代理配置类)

package com.xiaohui.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableFeignClients
/*** 激活HystrixDashboard仪表盘*/
@EnableDiscoveryClient
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class,args);}
}

4,业务类

controller

package com.xiaohui.springcloud.controller;import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.entities.Payment;
import com.xiaohui.springcloud.service.IPaymentService;
import com.xiaohui.springcloud.service.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OrderController {@Autowiredprivate IPaymentService paymentService;@GetMapping("/consumer/payment/insert")public CommonResult insert(){CommonResult insert = paymentService.insert();return insert;}
}

service

package com.xiaohui.springcloud.service;import com.xiaohui.springcloud.entities.CommonResult;public interface IPaymentService {CommonResult insert();
}

serviceImpl,在该类的方法上添加@GlobalTransactional(name = "weiyi-anystr-service",rollbackFor = Exception.class) 注解 表示对该类开启分布式事务,该类中的调用其他微服务以及级联的其他服务和本方法中操作本应用的数据库都将保持事务同步。 name 可以进行自定义取名,唯一即可。rollbackFor  表示发送什么异常时,都进行数据回滚。

package com.xiaohui.springcloud.service.impl;import com.xiaohui.springcloud.entities.CommonResult;
import com.xiaohui.springcloud.entities.Payment;
import com.xiaohui.springcloud.service.IPaymentService;
import com.xiaohui.springcloud.service.ProductFeignClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class PaymentServiceImpl implements IPaymentService {@Autowiredprivate ProductFeignClient productFeignClient;@Override@GlobalTransactional(name = "weiyi-anystr-service",rollbackFor = Exception.class)public CommonResult insert() {Payment payment = new Payment();payment.setSerial("this is test seata!");CommonResult insert = productFeignClient.insert(payment);int i= 1/0;return insert;}
}

六、测试验证

测试方式:

首次我们不添加@GlobalTransactional(name = "weiyi-anystr-service",rollbackFor = Exception.class) 注解。启动全部工程后进行调用消费者新增接口。会出现页面报错信息。并且生产者工程数据库数据新增成功。

第二次我们添加上@GlobalTransactional(name = "weiyi-anystr-service",rollbackFor = Exception.class) 注解。同样的请求,我们可以看到生产者工程数据库中数据并未有新增,以此证明远程调用中出现报错 数据都将进行回滚。

 

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/57864.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息