2.3 使用 TCC 模式接入 DTM
2.3.1 非微服务框架代码接入 DTM 样例指南
2.3.1.5 定义全局事务和分支事务
需要分别在bankA和bankB数据库中创建dtm_tran_info事务表。
2.3.1.5 定义全局事务和分支事务
在需要保证事务一致性的方法上使用注解:
@DTMTxBegin(appName = "xx")
其中,appName是全局事务的唯一标识。同时在在分支事务的try方法上使用注解:
@DTMTccBranch(identifier = "xx", confirmMethod = "xx", cancelMethod = "xx") 说明
confirm方法和cancel方法需要保证幂等性。
其中:
● identifier是分支事务的唯一标识。
● confirmMethod对应着无异常情况下执行的confirm方法。
● cancelMethod对应着发生异常情况下执行的cancel方法。
说明
● 当全局事务提交时,DTM通知分支事务执行confirm方法。
● 当全局事务回滚时,DTM通知分支事务执行cancel方法。
DTM全局事务发起者定义为transferTccLocal方法,transferTccLocal方法调用bankA转 入服务和bankB转出服务,同时根据设置选择性抛出异常。
// com.huawei.dtm.client.service:TransferService.java
@DTMTxBegin(appName = "transfer-tcc-local")
public void transferTccLocal(int id, int money, boolean exception) { bankAService.tryTransfer(id, money);
bankBService.tryTransfer(id, money);
if (exception) {
throw new RuntimeException("Add a potential exception");
} }
分支事务定义为tryTransferIn方法,全局事务中发生异常则执行cancel方法,没有发生 异常则执行confirm方法。
// com.huawei.banka.controller.BankAController.java
@DTMTccBranch(identifier = "tcc-try-transfer-in", confirmMethod = "confirm", cancelMethod =
"cancel")
public void tryTransfer(int id, int money) { bankAService.tryTransferIn(id, money);
}public void confirm() { bankAService.confirm();
}public void cancel() { bankAService.cancel();
}// com.huawei.common.impl.BankBController.java
@DTMTccBranch(identifier = "tcc-try-transfer-out", confirmMethod = "confirm", cancelMethod
= "cancel")
public void tryTransfer(int id, int money) { bankBService.tryTransferOut(id, money);
}public void confirm() { bankBService.confirm();
}public void cancel() { bankBService.cancel();
}
2.3.2 Spring Cloud 接入 DTM
本章节讲解Spring Cloud框架如何通过TCC模式接入DTM,使用DTM提供的分布式事 务处理能力,同时结合Spring Cloud接入DTM样例指南讲解接入的实现。
2.3.2.1 版本获取及引入依赖
步骤1 DTM使用Maven获取项目版本,根据样例中的settings文件设置Maven远程仓库地址 等配置。
步骤2 同时在项目的“pom.xml”文件中引入依赖,即可引入DTM Client的SDK。
<properties>
<!--以最新版本号为准-->
<dtm.version>3.0.4</dtm.version>
</properties>
<dependency>
<!--feign调用使用该依赖-->
<groupId>com.huawei.middleware.dtm</groupId>
<artifactId>dtm-springcloud-feign-starter</artifactId>
<version>${dtm.version}</version>
</dependency>
<dependency>
<!--rest调用使用该依赖-->
<groupId>com.huawei.middleware.dtm</groupId>
<artifactId>dtm-springcloud-rest-starter</artifactId>
<version>${dtm.version}</version>
</dependency>
----结束
2.3.2.2 数据源配置
在业务数据库上增加数据源DTMDataSource,从而实现DTM对业务数据的保护。
@Bean(name = "dataSource") public DataSource dtmDataSource() { //用DTM数据源来封装业务数据源
return new DTMDataSource(datasource);
}
在bankA服务中增加数据源DTMDataSource如下所示:
// com.huawei.banka.config.WebConfig.java;
@Bean(name = "bankDataSource")
@ConfigurationProperties(prefix = "spring.datasource.bank") public DataSource bankDataSource() {
return new DTMDataSource(datasource);
}
在bankB服务中增加数据源DTMDataSource如下所示:
// com.huawei.bankb.config.WebConfig.java
@Bean(name = "bankDataSource")
@ConfigurationProperties(prefix = "spring.datasource.bank") public DataSource bankDataSource() {
return new DTMDataSource(datasource);
2.3.2.3 添加客户端配置文件
在项目根目录中(jar包同级目录)新建dtm-config文件夹,并在dtm-config文件夹中 添加配置文件dtmClientConfig.properties。配置文件内容如下:
auto-create-table-dtm-tran-info=on dtm-app-name=xxxx
sc-server-address=xxxx rpc-ssl-switch=off
配置项说明如表2-9所示。
表2-9 dtmClientConfig.properties 配置文件参数详解
参数 说明
auto-create-table-dtm-tran-info 是否自动创建DTM事务表dtm_tran_info,用来记录事务信 息。
● on:自动创建事务表,可跳过业务库中创建事务表。
● off:手动创建事务表,可参考业务库中创建事务表方 式二。
dtm-app-name 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“应用名称”得到。
参数 说明
sc-server-address 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“服务中心地址”得到。
rpc-ssl-switch 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“SSL开关”得到。
● on:开启SSL
● off:关闭SSL
2.3.2.4 业务库中创建事务表
在业务库中创建DTM事务表dtm_tran_info,用来记录事务信息。创建有以下两种方 式,推荐通过修改DTM配置信息,自动创建DTM事务表。
● 方式一:自动创建,修改dtm配置文件dtmClientConfig.properties中auto-create-table-dtm-tran-info参数为on,开启自动创建。
auto-create-table-dtm-tran-info=on
● 方式二:手动创建,在原有基础上再创建事务数据库表。
a. 如果数据库使用MySQL或GaussDB(for MySQL),执行下面的SQL:
CREATE TABLE dtm_tran_info ( branch_id bigint(20) NOT NULL, global_id bigint(20) NOT NULL, tran_info longblob NOT NULL, info_status int(11) NOT NULL, info_created datetime(0) NOT NULL,
ext varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (branch_id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3571 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
b. 如果数据库使用PostgreSQL或GaussDB(openGauss),执行下面的SQL:
CREATE TABLE dtm_tran_info (
branch_id bigint NOT NULL primary key , global_id bigint NOT NULL,
tran_info text NOT NULL, info_status int NOT NULL,
info_created timestamp NOT NULL, ext varchar(100)
)
需要分别在bankA和bankB数据库中创建dtm_tran_info事务表。
2.3.2.5 定义全局事务和分支事务
在需要保证事务一致性的方法上使用注解:
@DTMTxBegin(appName = "xx")
其中,appName是全局事务的唯一标识。同时在在分支事务的try方法上使用注解:
@DTMTccBranch(identifier = "xx", confirmMethod = "xx", cancelMethod = "xx")
说明
confirm方法和cancel方法需要保证幂等性。
其中:
● identifier是分支事务的唯一标识。
● confirmMethod对应着无异常情况下执行的confirm方法。
● cancelMethod对应着发生异常情况下执行的cancel方法。
说明
● 当全局事务提交时,DTM通知分支事务执行confirm方法。
● 当全局事务回滚时,DTM通知分支事务执行cancel方法。
DTM全局事务发起者定义为transferTcc方法,该方法通过微服务接口调用bankA转入 的try方法和bankB转出的try方法,同时根据设置选择性抛出异常。
// com.huawei.bankcenter.controller.BankCenterController.java
@GetMapping(value = "transferTcc")
@DTMTxBegin(appName = "tcc-transfer-SpringCloud")
public String transferTcc(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money,
@RequestParam(value = "exception") boolean exception) {
LOGGER.info("Bank-center start invoke bankA and bankB by tcc_mode");
bankOperator.transferTcc(id, money);
if (exception) {
throw new RuntimeException("Add a potential exception");
}
return "ok";
}// bankOperator有两个实现类,下面以FeignOpImpl的实现类为例 // com.huawei.bankcenter.impl.FeignOpImpl.java
public String transferTcc(int userId, int money) { LOGGER.info("Start tcc---feign");
bankAIntf.transferTcc(userId, money);
bankBIntf.transferTcc(userId, money);
return "ok";
}
分支事务定义为tryTransferIn方法,全局事务中发生异常则执行cancel方法,没有发生 异常则执行confirm方法。
// com.huawei.banka.controller.BankAController.java
@GetMapping(value = "transferTcc")
@DTMTccBranch(identifier = "tcc-try-transfer-in", confirmMethod = "confirm", cancelMethod =
"cancel")
public void tryTransferIn(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money) {
bankAService.tryTransferIn(id, money);
}public void confirm() { bankAService.confirm();
}public void cancel() { bankAService.cancel();
}// com.huawei.common.impl.BankBController.java
@GetMapping(value = "transferTcc")
@DTMTccBranch(identifier = "tcc-try-transfer-out", confirmMethod = "confirm", cancelMethod
= "cancel")
public void tryTransferOut(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money) {
bankBService.tryTransferOut(id, money);
}public void confirm() { bankBService.confirm();
}public void cancel() { bankBService.cancel();
}
2.3.3 Spring Cloud Huawei 接入 DTM
本章节讲解Spring Cloud Huawei框架如何通过TCC模式接入DTM,使用DTM提供的分 布式事务处理能力,同时结合Spring Cloud Huawei接入DTM样例指南讲解接入的实 现。
2.3.3.1 版本获取及引入依赖
步骤1 DTM使用Maven获取项目版本,根据样例中的settings文件设置Maven远程仓库地址 等配置。
步骤2 同时在项目的“pom.xml”文件中引入依赖,即可引入DTM Client的SDK。
<properties>
<!--以最新版本号为准-->
<dtm.version>3.0.4</dtm.version>
</properties>
<dependency>
<!--feign调用使用该依赖-->
<groupId>com.huawei.middleware.dtm</groupId>
<artifactId>dtm-springcloud-feign-starter</artifactId>
<version>${dtm.version}</version>
</dependency>
<dependency>
<!--rest调用使用该依赖-->
<groupId>com.huawei.middleware.dtm</groupId>
<artifactId>dtm-springcloud-rest-starter</artifactId>
<version>${dtm.version}</version>
</dependency>
----结束
2.3.3.2 数据源配置
在业务数据库上增加数据源DTMDataSource,从而实现DTM对业务数据的保护。
@Bean(name = "dataSource") public DataSource dtmDataSource() { //用DTM数据源来封装业务数据源
return new DTMDataSource(datasource);
}
在bankA服务中增加数据源DTMDataSource如下所示:
// com.huawei.banka.config.WebConfig.java;
@Bean(name = "bankDataSource")
@ConfigurationProperties(prefix = "spring.datasource.bank") public DataSource bankDataSource() {
return new DTMDataSource(datasource);
}
在bankB服务中增加数据源DTMDataSource如下所示:
// com.huawei.bankb.config.WebConfig.java
@Bean(name = "bankDataSource")
@ConfigurationProperties(prefix = "spring.datasource.bank") public DataSource bankDataSource() {
return new DTMDataSource(datasource);
2.3.3.3 添加客户端配置文件
在项目根目录中(jar包同级目录)新建dtm-config文件夹,并在dtm-config文件夹中 添加配置文件dtmClientConfig.properties。配置文件内容如下:
auto-create-table-dtm-tran-info=on dtm-app-name=xxxx
sc-server-address=xxxx rpc-ssl-switch=off
配置项说明如表 dtmClientConfig配置文件参数详解所示。
表2-10 dtmClientConfig.properties 配置文件参数详解
参数 说明
auto-create-table-dtm-tran-info 是否自动创建DTM事务表dtm_tran_info,用来记录事务信 息。
● on:自动创建事务表,可跳过3.3.4-业务库中创建事务 表。
● off:手动创建事务表,可参考3.3.4-业务库中创建事务 表方式二。
dtm-app-name 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“应用名称”得到。
sc-server-address 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“服务中心地址”得到。
rpc-ssl-switch 该配置项可从“应用管理与运维平台”控制台“分布式事 务管理 DTM > 引擎实例”界面中“服务发现与配置”模 块“SSL开关”得到。
● on:开启SSL
● off:关闭SSL
2.3.3.4 业务库中创建事务表
在业务库中创建DTM事务表dtm_tran_info,用来记录事务信息。创建有以下两种方 式,推荐通过修改DTM配置信息,自动创建DTM事务表。
● 方式一:自动创建,修改dtm配置文件dtmClientConfig.properties中auto-create-table-dtm-tran-info参数为on,开启自动创建。
auto-create-table-dtm-tran-info=on
● 方式二:手动创建,在原有基础上再创建事务数据库表。
a. 如果数据库使用MySQL或GaussDB(for MySQL),执行下面的SQL:
CREATE TABLE dtm_tran_info ( branch_id bigint(20) NOT NULL, global_id bigint(20) NOT NULL, tran_info longblob NOT NULL, info_status int(11) NOT NULL, info_created datetime(0) NOT NULL,
ext varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (branch_id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3571 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
b. 如果数据库使用PostgreSQL或GaussDB(openGauss),执行下面的SQL:
CREATE TABLE dtm_tran_info (
branch_id bigint NOT NULL primary key , global_id bigint NOT NULL,
tran_info text NOT NULL, info_status int NOT NULL,
info_created timestamp NOT NULL, ext varchar(100)
)
需要分别在bankA和bankB数据库中创建dtm_tran_info事务表。
2.3.3.5 定义全局事务和分支事务
在需要保证事务一致性的方法上使用注解:
@DTMTxBegin(appName = "xx")
其中,appName是全局事务的唯一标识。同时在在分支事务的try方法上使用注解:
@DTMTccBranch(identifier = "xx", confirmMethod = "xx", cancelMethod = "xx") 说明
confirm方法和cancel方法需要保证幂等性。
其中:
● identifier是分支事务的唯一标识。
● confirmMethod对应着无异常情况下执行的confirm方法。
● cancelMethod对应着发生异常情况下执行的cancel方法。
说明
● 当全局事务提交时,DTM通知分支事务执行confirm方法。
● 当全局事务回滚时,DTM通知分支事务执行cancel方法。
DTM全局事务发起者定义为transferTcc方法,该方法通过微服务接口调用bankA转入 的try方法和bankB转出的try方法,同时根据设置选择性抛出异常。
// com.huawei.bankcenter.controller.BankCenterController.java
@GetMapping(value = "transferTcc")
@DTMTxBegin(appName = "tcc-transfer-SpringCloudHW")
public String transferTcc(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money,
@RequestParam(value = "exception") boolean exception) {
LOGGER.info("Bank-center start invoke bankA and bankB by tcc_mode");
bankOperator.transferTcc(id, money);
if (exception) {
throw new RuntimeException("Add a potential exception");
}
return "ok";
}// bankOperator 有两个实现类,下面以 FeignOpImpl 的实现类为例 // com.huawei.bankcenter.impl.FeignOpImpl.java
public String transferTcc(int userId, int money) { LOGGER.info("Start tcc---feign");
bankAIntf.transferTcc(userId, money);
bankBIntf.transferTcc(userId, money);
return "ok";
}
分支事务定义为tryTransferIn方法,全局事务中发生异常则执行cancel方法,没有发生 异常则执行confirm方法。
// com.huawei.banka.controller.BankAController.java
@GetMapping(value = "transferTcc")
@DTMTccBranch(identifier = "tcc-try-transfer-in", confirmMethod = "confirm", cancelMethod =
"cancel")
public void tryTransferIn(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money) {
bankAService.tryTransferIn(id, money);
}public void confirm() { bankAService.confirm();
}public void cancel() { bankAService.cancel();
}// com.huawei.common.impl.BankBController.java
@GetMapping(value = "transferTcc")
@DTMTccBranch(identifier = "tcc-try-transfer-out", confirmMethod = "confirm", cancelMethod
= "cancel")
public void tryTransferOut(@RequestParam(value = "id") int id, @RequestParam(value =
"money") int money) {
bankBService.tryTransferOut(id, money);
}public void confirm() { bankBService.confirm();
}public void cancel() { bankBService.cancel();
}
2.3.4 ServiceComb 接入 DTM
本章节讲解ServiceComb框架如何通过TCC模式接入DTM,使用DTM提供的分布式事 务处理能力,同时结合ServiceComb接入DTM样例指南讲解接入的实现。
2.3.4.1 版本获取及引入依赖
步骤1 DTM使用Maven获取项目版本,根据样例中的settings文件设置Maven远程仓库地址
步骤1 DTM使用Maven获取项目版本,根据样例中的settings文件设置Maven远程仓库地址