1 Seata
Seata实现分布式事务基础知识:https://blog.csdn.net/ZGL_cyy/article/details/113829282
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳的度过历年的双11,对各BU业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019.1 为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,开放以来,广受欢迎,不到一年已经成为最受欢迎的分布式事务解决方案。
官方中文网:https://seata.io/zh-cn
github项目地址:https://github.com/seata/seata
官方example:https://github.com/seata/seata-samples
1.1 Seata术语
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
Seata 致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
1.2 Seata AT模式
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。其中AT模式最受欢迎,使用也非常简单,但它内在的原理不简单。
AT模式的相关资料请参考官方文档说明:https://seata.io/zh-cn/docs/overview/what-is-seata.html
下图是AT模式的执行流程:
1.2.1 AT模式及工作流程
见官方文档:https://seata.io/zh-cn/docs/overview/what-is-seata.html
1.2.2 Seata-Server安装
我们在选择用Seata版本的时候,可以先参考下官方给出的版本匹配(Seata版本也可以按自己的要求选择):
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
我们当前SpringCloud Alibaba
的版本是2.2.5.RELEASE
,对应Seata版本是1.3.0,所以我们首先安装Seata-Server1.3.0
我们直接基于docker启动得到:
docker run --name seata-server -p 8091:8091 -d -e SEATA_IP=192.168.200.200 -e SEATA_PORT=8091 --restart=on-failure seataio/seata-server:1.3.0
1.2.3 集成springcloud-alibaba
我们接下来开始在项目中集成使用Seata的AT模式实现分布式事务控制,关于如何集成,官方也给出了很多例子,可以通过
https://github.com/seata/seata-samples
所以各种集成模式需要大家都自行的去翻看对应的samples
。
集成可以按照如下步骤实现:
1:引入依赖包spring-cloud-starter-alibaba-seata 2:配置Seata 3:创建代理数据源 4:@GlobalTransactional全局事务控制
案例需求:
如上图,如果用户打车成功,需要修改司机状态、下单、记录支付日志,而每个操作都是调用了不同的服务,比如此时hailtaxi-driver服务执行成功了,但是hailtaxi-order有可能执行失败了,这时候如何实现跨服务事务回滚呢?这就要用到分布式事务。
鉴于我们一般事务都是在service层进行的管理,所以,改造一下hailtaxi-order中的OrderInfoController#add
方法,将业务实现放到对应的Service中
/*** * 下单 */ /*@PostMapping public OrderInfo add(){ //修改司机信息 司机ID=1 Driver driver = driverFeign.status("3",2); //创建订单 OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", driver); orderInfoService.add(orderInfo); return orderInfo; }*/ @PostMapping public OrderInfo add() { return orderInfoService.addOrder(); }
在Service
实现中:
@Service public class OrderInfoServiceImpl implements OrderInfoService { @Autowired private DriverFeign driverFeign; /** * 1、修改司机信息 司机ID=1 * 2、创建订单 * @return */ @Override public OrderInfo addOrder() { //创建订单 OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", null); int count = orderInfoMapper.add(orderInfo); System.out.println("====count="+count); //修改司机信息 司机ID=1 Driver driver = driverFeign.status("1",2); orderInfo.setDriver(driver); return orderInfo; } }
案例实现:
0) 创建undo_log
表
在每个数据库中都需要创建该表:
CREATE TABLE `undo_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `branch_id` bigint(20) NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int(11) NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1)依赖引入
我们首先在hailtaxi-driver
和hailtaxi-order
中引入依赖:
<!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.2.5.RELEASE</version> </dependency>
2)配置Seata
依赖引入后,我们需要在项目中配置SeataClient
端信息,关于SeataClient端配置信息,官方也给出了很多版本的模板,可以参考官方项目:
https://github.com/seata/seata/tree/1.3.0/script,如下图:
我们可以选择spring,把application.yml
文件直接拷贝到工程中,文件如下:
完整文件内容见:https://github.com/seata/seata/blob/1.3.0/script/client/spring/application.yml
修改后我们在hailtaxi-driver
和hailtaxi-order
项目中配置如下:
seata: enabled: true application-id: ${spring.application.name} tx-service-group: my_seata_group enable-auto-data-source-proxy: true use-jdk-proxy: false excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude client: rm: async-commit-buffer-limit: 1000 report-retry-count: 5 table-meta-check-enable: false report-success-enable: false saga-branch-register-enable: false lock: retry-interval: 10 retry-times: 30 retry-policy-branch-rollback-on-conflict: true tm: degrade-check: false degrade-check-period: 2000 degrade-check-allow-times: 10 commit-retry-count: 5 rollback-retry-count: 5 undo: data-validation: true log-serialization: jackson log-table: undo_log only-care-update-columns: true log: exceptionRate: 100 service: vgroup-mapping: my_seata_group: default grouplist: default: 192.168.200.200:8091 enable-degrade: false disable-global-transaction: false transport: shutdown: wait: 3 thread-factory: boss-thread-prefix: NettyBoss worker-thread-prefix: NettyServerNIOWorker server-executor-thread-prefix: NettyServerBizHandler share-boss-worker: false client-selector-thread-prefix: NettyClientSelector client-selector-thread-size: 1 client-worker-thread-prefix: NettyClientWorkerThread worker-thread-size: default boss-thread-size: 1 type: TCP server: NIO heartbeat: true serialization: seata compressor: none enable-client-batch-send-request: true
关于配置文件内容参数比较多,我们需要掌握核心部分:
seata_transaction: default:事务分组,前面的seata_transaction可以自定义,通过事务分组很方便找到集群节点信息。
tx-service-group: seata_transaction:指定应用的事务分组,和上面定义的分组前部分保持一致。
default: 192.168.200.200:8091:服务地址,seata-server服务地址。
注意:
现在配置信息都是托管到nacos中的,所以可以直接将配置存储到nacos中
hailtaxi-order
hailtaxi-driver