Hmily TCC模式深度剖析:从理论到实践的完整指南
【免费下载链接】hmily Distributed transaction solutions 项目地址: https://gitcode.com/gh_mirrors/hm/hmily
分布式事务的痛点与TCC解决方案
你是否还在为分布式系统中的数据一致性问题头疼?在微服务架构下,传统单机事务(ACID)已无法满足跨服务调用场景,分布式事务(Distributed Transaction)成为保证数据一致性的关键技术。然而,常见的2PC(两阶段提交)方案存在性能瓶颈,Saga模式又难以处理复杂业务逻辑回滚。Hmily作为一款金融级柔性分布式事务解决方案,其TCC(Try-Confirm-Cancel)模式通过业务侵入式设计,在性能与一致性之间取得了完美平衡。
读完本文你将掌握:
- TCC模式的核心原理与Hmily实现机制
- 从零开始的Hmily TCC集成步骤(以Spring Cloud为例)
- 高并发场景下的TCC优化策略与最佳实践
- 常见问题诊断与解决方案(含完整代码示例)
TCC模式理论基础
TCC三阶段模型
TCC模式将分布式事务拆分为三个明确的操作阶段,通过业务逻辑的拆分实现分布式场景下的最终一致性:
各阶段职责:
- Try阶段:检查并预留业务资源(如扣减库存前锁定商品数量)
- Confirm阶段:确认执行业务操作,不做业务检查(如实际扣减库存)
- Cancel阶段:取消执行业务操作,释放预留资源(如释放锁定的商品数量)
Hmily TCC架构设计
Hmily采用分层架构设计,通过拦截器和事务上下文传递实现TCC模式的自动化管理:
核心组件说明:
- 事务协调器:管理全局事务状态,协调各参与者的Confirm/Cancel操作
- 事务拦截器:基于AOP拦截@HmilyTCC注解方法,自动传递事务上下文
- 参与者管理器:维护分布式事务参与者列表,处理幂等性与重试机制
Hmily TCC快速集成指南
环境准备与依赖配置
前置要求:
- JDK 8+
- Spring Cloud Greenwich.SR2+
- Maven 3.5+
- MySQL 5.7+(事务日志存储)
1. 添加Maven依赖
<!-- Hmily Spring Cloud Starter -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>hmily-spring-boot-starter-springcloud</artifactId>
<version>2.1.1</version>
</dependency>
<!-- Hmily TCC核心依赖 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>hmily-tcc</artifactId>
<version>2.1.1</version>
</dependency>
<!-- 事务日志存储(MySQL) -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>hmily-repository-database-mysql</artifactId>
<version>2.1.1</version>
</dependency>
2. 配置application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/hmily_tcc?useUnicode=true&characterEncoding=utf8
username: root
password: root
hmily:
service:
appName: order-service # 当前微服务名称
serializer:
type: kryo # 序列化方式:kryo/fst/hessian
repository:
database:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/hmily?useUnicode=true&characterEncoding=utf8
username: root
password: root
tcc:
delayCancelExe: 60 # 延迟取消执行时间(秒)
retryMax: 3 # 最大重试次数
scheduledDelay: 60 # 定时任务延迟时间(秒)
scheduledThreadMax: 10 # 定时任务线程池大小
代码实现(订单-库存-账户场景)
以电商下单场景为例,实现一个完整的TCC分布式事务:
1. 创建TCC注解接口
public interface OrderService {
/**
* 创建订单(TCC事务入口)
*/
@HmilyTCC(confirmMethod = "confirmCreateOrder", cancelMethod = "cancelCreateOrder")
OrderDTO createOrder(OrderDTO orderDTO);
/**
* Confirm阶段:确认创建订单
*/
void confirmCreateOrder(OrderDTO orderDTO);
/**
* Cancel阶段:取消创建订单
*/
void cancelCreateOrder(OrderDTO orderDTO);
}
2. 实现TCC业务逻辑
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryFeignClient inventoryFeignClient; // 库存服务Feign客户端
@Autowired
private AccountFeignClient accountFeignClient; // 账户服务Feign客户端
@Override
@Transactional
public OrderDTO createOrder(OrderDTO orderDTO) {
// 1. 本地保存订单(状态:PENDING)
OrderDO orderDO = new OrderDO();
BeanUtils.copyProperties(orderDTO, orderDO);
orderDO.setStatus(OrderStatus.PENDING);
orderMapper.insert(orderDO);
// 2. 调用库存服务扣减库存(TCC参与者)
InventoryDTO inventoryDTO = new InventoryDTO();
inventoryDTO.setProductId(orderDTO.getProductId());
inventoryDTO.setQuantity(orderDTO.getQuantity());
inventoryFeignClient.decrease(inventoryDTO);
// 3. 调用账户服务扣减余额(TCC参与者)
AccountDTO accountDTO = new AccountDTO();
accountDTO.setUserId(orderDTO.getUserId());
accountDTO.setAmount(orderDTO.getTotalAmount());
accountFeignClient.decrease(accountDTO);
return orderDTO;
}
@Override
public void confirmCreateOrder(OrderDTO orderDTO) {
// 更新订单状态为已确认
OrderDO orderDO = new OrderDO();
orderDO.setOrderNo(orderDTO.getOrderNo());
orderDO.setStatus(OrderStatus.CONFIRMED);
orderMapper.updateStatus(orderDO);
}
@Override
public void cancelCreateOrder(OrderDTO orderDTO) {
// 更新订单状态为已取消
OrderDO orderDO = new OrderDO();
orderDO.setOrderNo(orderDTO.getOrderNo());
orderDO.setStatus(OrderStatus.CANCELED);
orderMapper.updateStatus(orderDO);
}
}
3. 库存服务TCC实现
@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
@Override
@HmilyTCC(confirmMethod = "confirmDecrease", cancelMethod = "cancelDecrease")
public boolean decrease(InventoryDTO inventoryDTO) {
// Try阶段:锁定库存(预扣减)
return inventoryMapper.lock(inventoryDTO) > 0;
}
public boolean confirmDecrease(InventoryDTO inventoryDTO) {
// Confirm阶段:实际扣减库存
return inventoryMapper.decrease(inventoryDTO) > 0;
}
public boolean cancelDecrease(InventoryDTO inventoryDTO) {
// Cancel阶段:释放锁定的库存
return inventoryMapper.unlock(inventoryDTO) > 0;
}
}
4. 数据库表设计
-- 订单表
CREATE TABLE `order_tbl` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`user_id` varchar(64) NOT NULL COMMENT '用户ID',
`product_id` varchar(64) NOT NULL COMMENT '商品ID',
`quantity` int(11) NOT NULL COMMENT '数量',
`total_amount` decimal(10,2) NOT NULL COMMENT '总金额',
`status` int(2) NOT NULL COMMENT '状态:0-待确认,1-已确认,2-已取消',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
-- 库存表
CREATE TABLE `inventory_tbl` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_id` varchar(64) NOT NULL COMMENT '商品ID',
`total_inventory` int(11) NOT NULL COMMENT '总库存',
`locked_inventory` int(11) NOT NULL DEFAULT '0' COMMENT '锁定库存',
`available_inventory` int(11) NOT NULL COMMENT '可用库存',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存表';
Hmily TCC核心原理
事务上下文传递机制
Hmily通过拦截器和ThreadLocal实现事务上下文的跨服务传递:
关键代码在TccMethodInterceptor中实现:
public class TccMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取TCC注解信息
HmilyTCC hmilyTCC = AnnotationUtils.getAnnotation(invocation.getMethod(), HmilyTCC.class);
// 创建或获取事务上下文
HmilyTransactionContext context = HmilyTransactionContextLocal.getInstance().get();
if (context == null) {
context = new HmilyTransactionContext();
context.setTransType(hmilyTCC.pattern().name());
// 创建新的全局事务
HmilyTransaction transaction = HmilyTransactionManager.getInstance().begin(context);
context.setTransId(transaction.getTransId());
}
// 执行目标方法
Object result = invocation.proceed();
// 提交事务(仅发起者执行)
if (context.getRole() == HmilyRoleEnum.START.getCode()) {
HmilyTransactionManager.getInstance().commit();
}
return result;
}
}
事务补偿机制
Hmily通过定时任务对悬挂事务进行补偿处理,确保最终一致性:
高级特性与性能优化
幂等性设计
TCC模式下必须保证Confirm/Cancel操作的幂等性,推荐实现方式:
- 基于唯一ID的幂等:
@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
@Autowired
private IdGenerator idGenerator; // 分布式ID生成器
@Override
public boolean confirmDecrease(InventoryDTO inventoryDTO) {
// 1. 生成幂等ID(事务ID+业务ID)
String idempotentId = inventoryDTO.getTransId() + "_" + inventoryDTO.getProductId();
// 2. 检查是否已处理
if (redisTemplate.hasKey("tcc:confirm:" + idempotentId)) {
return true; // 已处理,直接返回成功
}
// 3. 执行扣减操作
int rows = inventoryMapper.decrease(inventoryDTO);
// 4. 标记已处理(设置过期时间,如24小时)
if (rows > 0) {
redisTemplate.opsForValue().set("tcc:confirm:" + idempotentId, "1", 24, TimeUnit.HOURS);
return true;
}
return false;
}
}
- 基于状态机的幂等:在数据库表中增加状态字段,通过乐观锁控制
并发控制策略
高并发场景下TCC模式可能出现资源竞争,推荐采用以下控制策略:
| 策略 | 实现方式 | 适用场景 | 性能影响 |
|---|---|---|---|
| 悲观锁 | SELECT ... FOR UPDATE | 写冲突频繁 | 低 |
| 乐观锁 | WHERE version = ? | 写冲突较少 | 高 |
| 分布式锁 | Redis/ZooKeeper | 跨服务资源竞争 | 中 |
乐观锁实现示例:
-- 乐观锁更新库存
UPDATE inventory_tbl
SET available_inventory = available_inventory - #{quantity},
version = version + 1
WHERE product_id = #{productId}
AND available_inventory >= #{quantity}
AND version = #{version}
性能优化实践
- 异步Confirm/Cancel:非核心流程采用异步执行
hmily:
tcc:
asyncConfirm: true # 异步Confirm
asyncCancel: true # 异步Cancel
executor:
threadMax: 20 # 异步线程池大小
-
本地消息表优化:将事务日志写入本地数据库,避免远程调用
-
批量处理:合并多个小事务为一个大事务,减少网络开销
常见问题与解决方案
1. 事务悬挂问题
问题描述:Cancel操作比Try操作先执行,导致资源无法正确释放。
解决方案:在Cancel方法中增加前置检查:
public void cancelCreateOrder(OrderDTO orderDTO) {
// 检查Try操作是否已执行
OrderDO orderDO = orderMapper.selectByOrderNo(orderDTO.getOrderNo());
if (orderDO == null || orderDO.getStatus() == OrderStatus.INIT) {
// Try未执行,直接返回成功
return;
}
// 执行Cancel逻辑
orderMapper.updateStatus(orderDTO.getOrderNo(), OrderStatus.CANCELED);
}
2. 空回滚问题
问题描述:当Try操作超时未执行,触发Cancel操作。
解决方案:增加Try操作的状态记录:
public OrderDTO createOrder(OrderDTO orderDTO) {
// 1. 插入订单记录(状态:INIT)
orderMapper.insert(new OrderDO(orderDTO, OrderStatus.INIT));
try {
// 2. 执行远程调用
inventoryFeignClient.decrease(inventoryDTO);
accountFeignClient.decrease(accountDTO);
// 3. 更新状态为TRY_SUCCESS
orderMapper.updateStatus(orderDTO.getOrderNo(), OrderStatus.TRY_SUCCESS);
} catch (Exception e) {
// 4. 更新状态为TRY_FAIL
orderMapper.updateStatus(orderDTO.getOrderNo(), OrderStatus.TRY_FAIL);
throw e;
}
}
3. 幂等性失效
问题描述:重试机制导致重复扣减库存或金额。
解决方案:基于Redis实现分布式锁:
public boolean confirmDecrease(InventoryDTO inventoryDTO) {
String lockKey = "tcc:lock:" + inventoryDTO.getProductId();
try (RedisLock lock = new RedisLock(redisTemplate, lockKey, 5000)) {
if (lock.acquire()) {
// 执行扣减逻辑
return inventoryMapper.decrease(inventoryDTO) > 0;
} else {
// 获取锁失败,认为已处理
return true;
}
}
}
完整代码示例与部署指南
项目结构
hmily-demo-tcc-springcloud/
├── hmily-demo-tcc-springcloud-order/ # 订单服务
├── hmily-demo-tcc-springcloud-inventory/ # 库存服务
├── hmily-demo-tcc-springcloud-account/ # 账户服务
└── hmily-demo-tcc-springcloud-eureka/ # 注册中心
部署步骤
- 克隆代码仓库
git clone https://gitcode.com/gh_mirrors/hm/hmily.git
cd hmily/hmily-demo/hmily-demo-tcc/hmily-demo-tcc-springcloud
- 初始化数据库
# 执行SQL脚本
mysql -uroot -p < ../../sql/hmily-demo.sql
- 启动服务
# 启动注册中心
cd hmily-demo-tcc-springcloud-eureka
mvn spring-boot:run
# 启动库存服务
cd ../hmily-demo-tcc-springcloud-inventory
mvn spring-boot:run
# 启动账户服务
cd ../hmily-demo-tcc-springcloud-account
mvn spring-boot:run
# 启动订单服务
cd ../hmily-demo-tcc-springcloud-order
mvn spring-boot:run
- 测试TCC事务
# 正常场景测试
curl -X POST http://localhost:8083/order/create \
-H "Content-Type: application/json" \
-d '{"userId":"1001","productId":"P001","quantity":2,"totalAmount":200.00}'
# 异常场景测试(库存不足)
curl -X POST http://localhost:8083/order/create \
-H "Content-Type: application/json" \
-d '{"userId":"1001","productId":"P001","quantity":9999,"totalAmount":999900.00}'
总结与展望
Hmily TCC模式通过精巧的架构设计,解决了分布式事务中的一致性与性能难题。本文从理论到实践详细介绍了TCC模式的实现原理、代码示例和最佳实践,重点关注了:
- TCC三阶段模型与Hmily事务协调机制
- 完整的Spring Cloud集成步骤与代码实现
- 高并发场景下的幂等性设计与性能优化
- 常见问题(悬挂、空回滚)的解决方案
随着微服务架构的普及,分布式事务将成为后端开发的必备技能。Hmily作为Dromara社区的重要项目,未来将支持更多RPC框架(如gRPC、Dubbo3)和存储引擎,为开发者提供更灵活的事务解决方案。
收藏本文,关注Hmily官方仓库,获取最新技术动态!
下期预告:《Hmily TAC模式详解:零侵入实现分布式事务》
【免费下载链接】hmily Distributed transaction solutions 项目地址: https://gitcode.com/gh_mirrors/hm/hmily
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



