SpringCloud Alibaba之Seata入门以及踩坑(二)

前言

上一篇文章:➣SpringCloud Alibaba之Seata入门以及踩坑(一)老顾介绍了seata相关的准备工作,以及版本的选择;今天老顾就来介绍一下seata的使用。以及在使用过程中遇到的问题。

案例背景

今天老顾介绍的案例场景也就是网上常用的场景,用户下单场景。整个流程就是用户下单时:

1)创建订单,订单状态为创建中

2)扣减商品库存

3)扣减用户金额

4)更改订单状态,订单状态为已完结

从以上业务流程,我们可以分为3个服务,如图

因为上面是3个分布式服务,事务问题就由此产生,我们来看看seata怎么来解决?

Client端准备

上文中已经介绍了seata-server的准备工作,需要首先启动seata服务。下面我们来看看client端项目需要做什么准备。

项目依赖

我们需要在项目中引入seata的jar包,有以下选择(任选其一):

  • 依赖seata-all 手动配置较多
  • 依赖seata-spring-boot-starter,支持yml配置
  • 依赖spring-cloud-starter-alibaba-seata,内部集成了seata,并实现了xid传递

注意:client 版本与 server端版本一致

上面三种方式,需要做不同的事情,尤其xid的传递是比较麻烦的,还好spring-cloud-starter-alibaba-seata已经帮我们实现,具体看看下图:

这里我们就用spring-cloud-starter-alibaba-seata方式。

因为我们seata-server用了1.3.0,所以我们client也需要同一版本。

数据库准备

3个微服务rb-order-server、rb-account-server、rb-storage-server我们就创建3个数据库。

seata-order库中创建t_order

seata-account库中创建t_account

seata_storage库中创建t_storage

项目新建undo_log表

每个微服务项目有独立的数据库,则需要在库中创建undo_log表

微服务项目中引入mybatis-plus操作数据库,这里老顾就不介绍了。

微服务配置

我们聚焦到seata相关上面;上文中我们seata-server服务是结合nacos的。

我们在rb-order-server、rb-account-server、rb-storage-server3个服务的application.yml配置文件中,都要配置相关seata的配置。

上面的配置比较容易理解,有几个地方很重要:

1)enable-auto-data-source-proxy

这个配置就是启动自动开启数据源代理。

2)tx-service-group:seata_test_tx_group

这个是事务分组,项目的微服务都要配置一样的事务分组,并且要和上文中的seata-server的service.vgroupMapping.seata_test_tx_group=default一致。

数据库代理

因为seata采用了DataSource代理方式操作数据,所以在springboot项目中先要排除datasource初始化,这样yml文件中的seata.enable-auto-data-source-proxy: true 自动代理才会生效。如何排除也是比较简单,三个服务都要排除,启动自动数据库代理。

以上client准备工作就结束了。

Feign调用

因为order服务中要调用account服务、storage服务,所以order中需要引入feign调用,如果把三个服务加入注册中心,能够互动调用;老顾这里就不介绍了,小伙伴们可以看老顾的以前的文章。

我们在来看看各个服务的具体实现。

项目服务代码

库存服务

上面的代码,能够发现如果下单的时候超过库存数,就会抛异常;

用户服务

上面的代码,如果扣减的金额超过用户金额时,就抛异常;

订单服务

上面的订单服务代码中,我们发现引入了@GlobalTransactional;对的,就是加入了@GlobalTransactional这个注解,就实现了分布式事务,简单吧。

我们可以启动postman,请求count参数为1的话,查看业务数据库数据都正常。对应的库存减少了1,金额减少了100,订单成功插入。

如果我们传入的count参数大于库存数,库存服务就会抛异常,那库存服务就会执行失败,这样订单服务,用户服务也会回滚。这样就起到了分布式事务作用。

感觉到这里,小伙伴们是不是感觉seata的强大,这个就是seata推荐的AT模式。

Feign降级坑

在我们微服务使用中,一旦微服务产生异常,我们都会用到降级的功能;如在调用库存服务的时候引入sentinel降级,这个知识老顾之前就介绍过,小伙伴们可以查看之前的文章。

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
feign:
  sentinel:
    enabled: true

这样对库存服务的降级处理是实现了,这也是正常的微服务的使用。

但是这样的处理,seata就会失效;我们发现count参数大于库存时,库存服务报异常,但因为有降级处理,订单还是提交了订单数据,用户金额还是减少了。事务不起作用了。

解决方式

官方推荐的方法,就是利用aop方式,手动处理全局事务回滚,我们在库存服务中加入aop

从上述代码中,我们用容易发现,如果执行的service中出现异常,就手动实现全局事务rollback。这样就解决了Feign的降级的问题。

注意:上面的aop代码中,before、after方法中,可以结合自身的业务 本案例中库存服务,只在抛异常的时候做了处理

总结

seata的分布式事务使用起来是非常简单的,但是seata的使用会对现有项目中产生一些意外的错误,但是都可以得到相应的解决;需要小伙伴去实践。谢谢!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章