基于tcc的Java分布式事务框架 - Duttor

专注人工智能在金融领域的应用

基于tcc的Java分布式事务框架

基于tcc的Java分布式事务框架 

支持范围

  • JDK6+
  • All RPC
  • Springframework 3.2+
  • MySQL

功能简介

  • 事务预提交
  • 事务确认提交
  • 事务回滚

Try: 尝试执行业务

  • 完成所有业务检查(一致性)
  • 预留必须业务资源(准隔离性)

Confirm: 确认执行业务

  • 真正执行业务
  • 不作任何业务检查
  • 只使用Try阶段预留的业务资源
  • Confirm操作满足幂等性

Cancel: 取消执行业务

  • 释放Try阶段预留的业务资源
  • Cancel操作满足幂等性

架构图

《基于tcc的Java分布式事务框架 》

业务操作

  • 业务组成:商城系统、库存系统和订单系统
  • 商城先调用减库存服务,然后再调用新增订单服务

《基于tcc的Java分布式事务框架 》事务表:在每个业务库中都增加一张事务表,通过延伸业务事务范围包扩对事务表的操作

《基于tcc的Java分布式事务框架 》

TX状态

《基于tcc的Java分布式事务框架 》

业务前置表/主表

  • 在对分布式操作的表都需要复制一份一模一样的表成为前置表
  • 业务查询操作都在主表上进行,数据强一致性
  • 业务DML操作首先在前置表上进行操作
  • 待所有前置业务表操作完毕,在同时同步到各自主表上
  • 取消时只需要在前置表上做UNDO操作

《基于tcc的Java分布式事务框架 》Action/Try

  • 只有一个Action入口
  • Try在前置表上进行操作
  • Try/Confirm/Cancel方法入参定义都一致

《基于tcc的Java分布式事务框架 》Confirm

《基于tcc的Java分布式事务框架 》

Cancel

《基于tcc的Java分布式事务框架 》

示例代码

@Override
@Transactional
@TXAction(value = TransactionTypeEnum.TCC,bizType = “purchase”)
public String purchase(SerialNumberGenerator generator, long userId, long productId, long amount){
TXContext ctx= TXContextHolder.getTXContext();
final JSONObject request= new JSONObject();
request.put(“txId”,ctx.getTxId());
request.put(“serialNumber”,ctx.getSerialNumber());
request.put(“productId”,productId);
request.put(“amount”,amount);
request.put(“userId”,userId);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<JSONObject> entity = new HttpEntity<JSONObject>(request, headers);
ResponseEntity<Boolean> result= restOperations.exchange(repositoryURL, HttpMethod.POST,entity, Boolean.class);
if(result.getBody()){
result= restOperations.exchange(orderURL, HttpMethod.POST,entity, Boolean.class);
if(result.getBody()){
return “购买产品成功”;

}
throw new RuntimeException(“生成订单操作失败.”);
}
else{
throw new RuntimeException(“减库存操作失败.”);
}
}

示例代码

  • Try/Confirm/Cancel方法都需要业务实现
  • Try/Confirm/Cancel方法入参定义和传入值都一样

@Transactional
@TXTry(cancel = “decreaseRepository” ,cancel = “increaseRepository”)
public boolean tryDecreaseRepository(TXContext ctx,long productId, long amount){
return 0 < dao.trydecrease(new RepositoryDO(productId, amount));
}
@Transactional
@TXConfirm
public boolean decreaseRepository(TXContext ctx,long productId,long amount){
return 0 < dao.increase(new RepositoryDO(productId, amount));
}
@Transactional
@TXCancel
public boolean increaseRepository(TXContext ctx,long productId,long amount){
return 0 < dao.increase(new RepositoryDO(productId, amount));
}

最终一致性保障

  • 通过消息系统传递的指令执行失败,通过调度任务重复执行

《基于tcc的Java分布式事务框架 》

阶梯时间重试

  • 调用Confirm或Cancel服务的时候,如果出错需要进行重试
  • 通过调度任务读取TX对应的重复次数,进行服务的重复调用
  • 按照阶梯时间调用服务,间隔是10*2   (单位为秒)

《基于tcc的Java分布式事务框架 》

后管平台

《基于tcc的Java分布式事务框架 》

Demo

  • galaxy-demo-purchase:商城系统
  • galaxy-demo-repository:库存系统
  • galaxy-demo-order:订单系统

测试用例

  • 正常下单:localhost:8080/purchase/rest/{quantity}
  • 模拟减库存失败:localhost:8080/purchase/rest/case/1
  • 模拟下单失败:localhost:8080/purchase/rest/case/2
  • 模拟减库存超时:localhost:8080/purchase/rest/case/3
  • 模拟下单超时:localhost:8080/purchase/rest/case/4

源码地址:https://github.com/Duttor/tcc-transaction

关于事务的基本介绍请参考上篇文章《事务的基本知识》:http://wangbaocai.cn/?p=1366

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>