不了解分布式事务的 看上篇文章点击这里

Seata集成实战

Seata须知

下面进入实战,环境: springBoot2.2.2 + springCloud Hoxton.SR1 + seata1.2.0 + Mysql5.7

首先我们要明白seata中的几个术语:

seatunnel 支持的flink cdc seata支持oracle吗_回滚

我们来想象一个场景,现在有一个微服务架构的电商系统,其中包含了订单服务、库存服务

他们分别部署在不同的服务器上,连接的也是不同的数据库。(以下的操作不考虑复杂情况)

现在用户对商品进行购买操作,我们要做两件事:

1.调用订单服务====> 针对用户下单的商品进行订单生成入库

2.调用库存服务====> 针对该商品进行库存削减

我们可以想到,订单项目和库存项目 每一个都是RM(资源管理器)

因为他们驱动着自己本地的分支事务提交或者回滚

如图:

seatunnel 支持的flink cdc seata支持oracle吗_数据库_02

·

那么TM是谁?

如果我们还有一个服务 用来专门处理业务,这个服务中会调用 订单服务,库存服务。那么他就应该是TM

因为这个业务服务,需要开始全局事务。

seatunnel 支持的flink cdc seata支持oracle吗_数据库_03

那么谁又是TC(事务协调者)

其实就是Seata服务。那么一会我们会开启seata服务。他就是TC

Seata与SpringBoot、Cloud集成

1. 下载seata1.2.0

seatunnel 支持的flink cdc seata支持oracle吗_seata连oracle_04

2. 创建数据库

这里注意:我们需要创建什么 这里的sql我会在后边粘贴,现在只需要知道创建什么即可。

a.创建单独的数据库(数据库名随意),用来记录分支信息等等

seatunnel 支持的flink cdc seata支持oracle吗_seata连oracle_05

b.在每个业务数据库中都要创建undo_log表(用于记录回滚操作的)

如图:订单服务连接distribute_order数据库,则需要创建一张undo_log , 库存服务连接的是distribute_store 也是如此

seatunnel 支持的flink cdc seata支持oracle吗_seata连oracle_06

编写order订单服务,store库存服务

编写过程略,我们只需要知道对数据库进行了什么操作即可

订单服务:连接distribute_order库,会插入一条记录进order表。

库存服务:连接distribute_store库,会根据购买的商品id,针对商品进行库存削减。

这里只贴出关键代码:

订单服务:

insert into `order`(onum) values (#{onum})

库存服务:

update good set count = count - 1 where id = #{id}

3.进入到重要环节: 修改seata-server的配置

3.1找到registry.conf并修改

seatunnel 支持的flink cdc seata支持oracle吗_spring_07

我们都知道微服务是有注册中心的(注册中心不懂说明不会微服务…),我们现在需要把seata服务注册到中心中

注册中心我用的是eureka,如图

seatunnel 支持的flink cdc seata支持oracle吗_回滚_08

所以我们修改registry.conf 主要就是type=“eureka” , 以及eureka的地址别写错了。

registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "eureka"
nacos {
application = "seata-server"
serverAddr = "localhost"
namespace = ""
cluster = "default"
username = ""
password = ""
}
eureka {
serviceUrl = "http://localhost:8761/eureka/"
application = "seata-server"
weight = "1"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "file"
file {
name = "file.conf"
}
}

3.2 修改file.conf

这个文件主要是配置seata-server连接的数据库,还记得我们在第二步创建的数据库吗

这里主要就是配置service模块 、和下面的db模块

#这里手动加入service模块
service {
#transaction service group mapping
#修改,可不改,my_test_tx_group随便起名字。
vgroup_mapping.my_test_tx_group = "default"
#only support when registry.type=file, please don't set multiple addresses
# 此服务的地址
default.grouplist = "127.0.0.1:8091"
#disable seata
disableGlobalTransaction = false
}
## transaction log store, only used in seata-server
store {
## store mode: file、db
mode = "db"
## 数据库连接的位置 重要
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
datasource = "druid"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/seata"
user = "root"
password = "mysql"
minConn = 5
maxConn = 30
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
}

4.修改项目文件集成seata功能

这一步主要是让我们的order服务,store服务、以及我们的业务服务。能够使用分布式事务

4.1修改pom文件 加入seata依赖

只要涉及分布式事务的项目,都加上 ! !

com.alibaba.cloud
spring-cloud-starter-alibaba-seata
2.2.1.RELEASE

4.2修改项目配置文件

这里大家可以修改properties文件/yml配置文件。加入以下的配置,当然yml和properties写法有些区别这里不多赘述。大家都懂

##############################[seata配置]###################################################
#是否使用分布式事物
seata:
enabled: true
application-id: seata-bus
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: true
service:
vgroup-mapping.my_test_tx_group: default
grouplist.default: localhost:8091
##############################[seata配置]###################################################

5.使用注解@GlobalTransactional开启分布式事务

这里调用了库存服务,又调用了订单服务

这是service业务层:

@GlobalTransactional
public String testGlobalTx(){
System.out.println("事务XID="+RootContext.getXID());
String url2 = "http://seata-store/update?id=1";
String result2 = restTemplate.getForObject(url2, String.class);
//如何消费provider的服务,重点问题
String url = "http://seata-order/insert?onum=shaoshuai";
String result = restTemplate.getForObject(url, String.class);
System.out.println("seata=============开始全局事务~~~");
return result;
}

顺便编写下controller

@RestController
public class TestController {
@Autowired
TestService tv;
@RequestMapping("/globalTx")
public String select() {
return tv.testGlobalTx();
}
}

测试结果

我们先看下整体的项目结构

seatunnel 支持的flink cdc seata支持oracle吗_spring_09

1.测试事务能否正确回滚(Rollback)

3.1 开启所有项目

eureka-server(注册中心),开启springcloud-seata(业务服务)、springcloud-order(订单服务)、springcloud-store(库存服务)

seatunnel 支持的flink cdc seata支持oracle吗_回滚_10

3.2 开启seata服务器

找到seata/bin目录下的seata-server.bat 开启

seatunnel 支持的flink cdc seata支持oracle吗_数据库_11

3.3 在订单接口里制造错误

![在这里插入图片描述]()

3.4 测试接口

我们刚才在订单接口中制造一个错误,是为了观察整个事务是否能正确回滚

如果库存依旧减少: 事务没有正确回滚。

库存没有减少: 事务可能回滚 / 事务没有执行 (我们需要观察seata的日志)

先来看一下数据库中的数据情况 订单表

seatunnel 支持的flink cdc seata支持oracle吗_spring_12

库存表 300个

seatunnel 支持的flink cdc seata支持oracle吗_数据库_13

测试接口访问

http://localhost:10005/globalTx

seatunnel 支持的flink cdc seata支持oracle吗_spring_14

报错了,没错 by / zero就是我们订单服务的错误

我们观察store服务执行了没,看日志

seatunnel 支持的flink cdc seata支持oracle吗_seata连oracle_15

其实是执行了的,我们再看数据库库存是否削减

seatunnel 支持的flink cdc seata支持oracle吗_回滚_16

没有削减,那么究竟是事务根本就没有生效 还是 事务已经生效了呢,我们观察seata服务器日志

seatunnel 支持的flink cdc seata支持oracle吗_数据库_17

其实已经rollback了,所以是没问题的。

到这文章就已经结束了。接下来是成功测试环节。

1.测试事务能否正确提交(Commit)

接下来把订单接口的错误取消,试试。

seatunnel 支持的flink cdc seata支持oracle吗_spring_18

访问接口:

http://localhost:10005/globalTx

seatunnel 支持的flink cdc seata支持oracle吗_seata连oracle_19

看数据库

seatunnel 支持的flink cdc seata支持oracle吗_spring_20

seatunnel 支持的flink cdc seata支持oracle吗_数据库_21

再看seata日志

seatunnel 支持的flink cdc seata支持oracle吗_spring_22