0.前言
简要说下背景,当前使用seata是基于官方1.5.2版本开发的,所以集成过程可供1.5.2及之后版本的使用者参考,为区别于官方版本,内部版本号设置为1.5.2.2。设计demo演示全局事务,执行流程如下。
demo业务流程设计
1.Seata客户端集成
1.1 引入依赖
<!-- springboot项目,引入seata-spring-boot-starter依赖 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2.2</version>
</dependency>
<!-- 为保证微服务间xid透传,引入此依赖(注意,需排除引入其他版本seata依赖的影响) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>1.5.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
项目seata相关依赖版本统一如下:
1.2 配置
以fundpay服务为例,配置文件中新增配置,主要为seata客户端服务配置注册中心及vgroupMapping
设置。
之后可启动seata-server服务端,再启动fundpay客户端服务查看是否正常启动及注册。如下日志即为客户端服务启动成功并成功注册到seata-server服务端时,seata-server服务端的输出(打印前两行日志即可视为成功)。
其他微服务按此方式集成注册。
集成成功后,服务间拓扑如下
2.AT事务模式开发配置
AT事务模式代码侵入性低,可以基本保持之前的代码结构,一般情况下,只需要在入口业务方法实现上添加@GlobalTransactional
注解即可。
原先接口主要代码实现如下:
在com.boss.fundpay.service.impl.PayServiceImpl#pay
业务实现方法上添加全局事务注解。
@Override
@GlobalTransactional(rollbackFor = Exception.class,timeoutMills = 60000)
public ApiResultDTO pay(PayInfoDto payInfo) throws Exception {
//1.记录当前操作
PayLog payLog = new PayLog();
BeanUtil.copyProperties(payInfo,payLog);
payLog.setBgtId(IdUtil.simpleUUID());
String curDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
payLog.setPayTime(curDate);
payLogDao.insertPayLog(payLog);
String orderNo = payInfo.getOrderNo();
String merchantId = payInfo.getMerchantId();
//2.调用流程审核
RiskAuditReq riskAuditReq = new RiskAuditReq();
riskAuditReq.setMerchantId(merchantId);
riskAuditReq.setOrderNo(orderNo);
ApiResultDTO workflowResult = workflowFeignApi.riskAudit(riskAuditReq);
if(Objects.isNull(workflowResult)||ApiResultDTO.hasError(workflowResult)
||(!PASS.equals(workflowResult.getResult()))){
throw new Exception();
}
//获取商户余额
MerchantBanlanceRecord record = merchantBalanceRecordDao.selectBalanceRecordById(merchantId);
BigDecimal balance = record.getTotalBalance().add(payInfo.getTotalAmount());
//3.调用记账
IncreaseBillReq increaseBillReq = new IncreaseBillReq();
increaseBillReq.setOrderNo(orderNo);
increaseBillReq.setAccountAmount(balance);
increaseBillReq.setMerchantId(merchantId);
ApiResultDTO accountResult = accountFeignApi.increaseBill(increaseBillReq);
if(Objects.isNull(accountResult)||ApiResultDTO.hasError(accountResult)){
throw new Exception();
}
//4.回写本地表
record.setPayType(payLog.getPayType());
record.setPayTime(payLog.getPayTime());
record.setOrderNo(payLog.getOrderNo());
record.setTotalAmount(payLog.getTotalAmount());
record.setTotalBalance(balance);
merchantBalanceRecordDao.updateBalanceRecord(record);
//创造异常触发回滚
// int a = RandomUtil.randomInt(10);
// if(a==5){
// int b=1/0;
// }
//完成
return ApiResultDTO.success("成功了 order="+orderNo+" ,merchantId="+merchantId+" ,balance="+balance);
}
在AT模式下,workflow服务和account服务的代码逻辑不需要调整。
3.TCC事务模式开发配置
3.1 两阶段提交回顾
回顾下官网描述,一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
- 一阶段 prepare 行为
- 二阶段 commit 或 rollback 行为
根据两阶段行为模式的不同,将分支事务划分为 Automatic (Branch) Transaction Mode 和 TCC (Branch) Transaction Mode。
AT 模式基于 支持本地 ACID 事务 的 关系型数据库:
- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
- 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
总之,TCC事务模式需要对代码逻辑进行重新设计,主要是需要按照 两阶段提交 的模型要求,开发自定义的分支事务,将其纳入全局事务的管理中。
3.2 接口实现方法拆分
如下面示例,pay
方法需要在接口层拆分出prepare
、confirm
、rollback
三个子方法,将对应的代码逻辑拆分到对应子方法实现中,其他服务也按此模型思想进行代码拆分。
fundpay实现拆分示例(仅拆分fundpay自身的业务DB操作,涉及远程调用的不需考虑,详情见下节)
workflow实现拆分示例
业务实现的粒度拆分需要开发人员合理把控
account服务拆分基本相同,这里省略。
3.3 入口业务方法独立
上节是将各个微服务的业务实现代码按照 二阶段提交 的思想进行了拆分,回到业务入口方法这里,不可能也不应该在fundpay服务拆分后的二阶段方法中执行远程调用,所以独立出单独的入口方法Action
,执行整体的业务逻辑(含服务间远程调用),将各分支事务纳入全局事务的控制中。
以上,即完成AT&TCC事务模式搭建演示。
标签:事务,Seata,CC,payLog,record,拆分,new,AT&T,seata From: https://www.cnblogs.com/zjfjava/p/17076949.html