微服务整合Seata1.5.2+Nacos2.2.1+SpringBoot
❤️《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。
❤️关注我,不迷路,你的支持是我最大的动力。
❤️学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。
❤️再小的收获x365天都会成就不一样的自己,一起学习,一起进步。
我们知道Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA四种事务模式
,为用户打造一站式的分布式解决方案,包括事务管理、本地事务协调、分布式事务日志和分布式锁等组件。
上一篇文章我们学习了Seata简介以及Seata Server端搭建,本篇文章了解一下Seata Client端搭建及Seata简单的应用。
本文版本环境: Spring Cloud Alibaba 2021.0.4.0 Spring Boot 2.6.11 Nacos 2.2.1 Seata1.5.2 |
一、Seata Client端搭建
1、为示例业务创建表
2、业务代码集成 Seata
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.11</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!--seata starter -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<!--nacos discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.3</version>
</dependency>
server:
port: 2001
spring:
application:
name: seata-order-service
cloud:
nacos:
discovery:
# 服务分组
group: SEATA_GROUP
server-addr: http://localhost:8848
# 必须填命名空间的ID
namespace: 891d7906-dd03-4b8c-9fe9-a1f0609b3189
datasource:
type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/seata_order?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false #useSSL安全加固
username: root
password: 12345678
# MyBatis Plus配置
mybatis-plus:
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapper-locations: classpath*:mapper/**/*.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.qytest.springcloud.entitites
global-config:
db-config:
id-type: auto
configuration:
# 开启驼峰,开启后,只要数据库字段和对象属性名字母相同,无论中间加多少下划线都可以识别
map-underscore-to-camel-case: true
# Seata 配置
seata:
application-id: seata-server
# 是否启用数据源bean的自动代理
enable-auto-data-source-proxy: false
tx-service-group: dev_tx_group # 必须和服务器配置一样
registry:
type: nacos
nacos:
# Nacos 服务地址
server-addr: http://localhost:8848
group: SEATA_GROUP
namespace: 891d7906-dd03-4b8c-9fe9-a1f0609b3189
application: seata-server # 必须和服务器配置一样
username: nacos
password: nacos
cluster: default
config:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
group: SEATA_GROUP
namespace: 891d7906-dd03-4b8c-9fe9-a1f0609b3189
service:
vgroup-mapping:
tx-service-group: dev_tx_group # 必须和服务器配置一样
disable-global-transaction: false
client:
rm:
# 是否上报成功状态
report-success-enable: true
# 重试次数
report-retry-count: 5
@RestController
@RequestMapping("")
@Slf4j
public class OrderController {
@Resource
private OrderService orderService;
@GetMapping("/order/create")
public CommonResult<Order> create(Order order) {
orderService.create(order);
return new CommonResult<Order>(200, "订单创建成功", order);
}
}
public interface OrderService extends IService<Order> {
void create(Order order);
}
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Resource
private StorageService storageService;
@Resource
private AccountService accountService;
/**
* 创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态
* 简单说:下订单->扣库存->减余额->改状态
*/
@Override
public void create(Order order) {
//1 新建订单
log.info("----->开始新建订单");
baseMapper.create(order);
log.info("----->新建订单完成");
//2 扣减库存
log.info("----->订单微服务开始调用库存,做扣减Count");
storageService.decrease(order.getProductId(), order.getCount());
log.info("----->库存扣减Count完成");
//3 扣减账户
log.info("----->订单微服务开始调用账户,做扣减Money");
accountService.decrease(order.getUserId(), order.getMoney());
log.info("----->账户扣减Money完成");
//4 修改订单状态,从0到1,1代表已经完成
log.info("----->修改订单状态开始");
baseMapper.update(order.getUserId(),0);
log.info("----->修改订单状态结束");
log.info("----->下订单结束了,O(∩_∩)O哈哈~");
}
}
# 先单机模式启动nacos
moon@moondeiMac ~ % cd /Users/moon/Downloads/nacos-2.2.1/distribution/target/nacos-server-2.2.1/nacos/bin
moon@moondeiMac bin % sh startup.sh -m standalone
# 再启动seata
moon@moondeiMac ~ % cd /Users/moon/Downloads/seata/bin
moon@moondeiMac bin % sh seata-server.sh
3、常见问题
二、 @GlobalTransactional
我们上面搭建了简单的用户购买商品的微服务系统:
1.创建订单->2.调用库存服务扣减库存->3.调用账户服务扣减账户余额->4.修改订单状态
简单说:下订单->扣库存->减余额->改状态
假设第3步扣减账户超时,在seata-account-service项目中模拟一个异常。不加 @GlobalTransactional 事务控制出现超时会数据异常,当库存和账户金额扣减后,订单状态并没有设置为已经完成,没有从零改为 1。而且由于 feign 的重试机制,账户余额还有可能被多次扣减。
验证异常未回滚如下:
/**
* 使用Seata对数据源进行代理
*/
@Configuration
public class DataSourceProxyConfig {
@Value("${mybatis-plus.mapper-locations}")
private String mapperLocations;
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource(){
return new DruidDataSource();
}
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean
public 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();
}
}
再次请求,发现数据库数据无变化,即全局事务回滚成功。
如果未成功,检查异常是否被catch或者有无熔断降级。
评论