# Seata TCC模式


<!--more-->


## 一. TCC模式介绍

Seata开源了TCC模式，该模式由蚂蚁⾦服贡献。TCC模式需要⽤户根据⾃⼰的业务场景实现Try、Confirm和Cancel三个操作；事务发起⽅在⼀阶段执⾏Try⽅式，在⼆阶段提交执⾏Confirm ⽅法，⼆阶段回滚执⾏Cancel⽅法。

![img_8](https://img.zhaojq.top/20260727091844310.png "img_8")

- Try：资源的检测和预留；
- Confirm：执⾏的业务操作提交；要求Try成功Confirm⼀定要能成功；
- Cancel：预留资源释放。

业务模型分2阶段设计：⽤户接⼊TCC，最重要的是考虑如何将⾃⼰的业务模型拆成两阶段来实现。

> 以“扣钱”场景为例，在接⼊TCC前，对A账户的扣钱，只需⼀条更新账户余额的SQL便能完成；但是在接⼊TCC之后，⽤户就需要考虑如何将原来⼀步就能完成的扣钱操作，拆成两阶段，实现成三个⽅法，并且保证⼀阶段Try成功的话⼆阶段Confirm⼀定能成功。
>
> ![img_9](https://img.zhaojq.top/20260727091844490.png "img_9")

**⽤户接⼊TCC模式，最重要的事情就是考虑如何将业务模型拆成2阶段，实现成TCC的3个⽅法，并且保证Try成功Confirm⼀定能成功。相对于AT模式，TCC模式对业务代码有⼀定的侵⼊性，但是TCC模式⽆AT模式的全局⾏锁，TCC性能会⽐AT模式⾼很多。**



## 二. TCC模式改造

### 2.1 RM端改造

针对RM端,实现起来需要完成try/commit/rollback的实现,所以步骤相对较多但是前三步骤和AT模式⼀样

![img_10](https://img.zhaojq.top/20260727091844682.png "img_10")

- 复制at工程为parent-seata-tcc-demo,用于tcc改造

- 修改数据库表结构,增加预留检查字段,⽤于提交和回滚

  ```mysql
  ALTER TABLE `seata_order`.`t_order` ADD COLUMN `status` int(0) NULL COMMENT'订单状态-0不可⽤,事务未提交,1-可⽤,事务提交';
  
  ALTER TABLE `seata_points`.`t_points` ADD COLUMN `frozen_points` int(0) NULL DEFAULT 0 COMMENT '冻结积分' AFTER `points`;
  
  ALTER TABLE `seata_storage`.`t_storage` ADD COLUMN `frozen_storage` int(0) NULL DEFAULT 0 COMMENT'冻结库存 'AFTER `goods_id`;
  ```

- 删除DataSourceConfiguration,因为tcc模式下用不到

- 去掉启动类数据源包扫描 @SpringBootApplication(scanBasePackages = "com.example", exclude = DataSourceAutoConfiguration.class)

- 具体修改见示例工程: [demo-seata-tcc-demo](git remote add origin https://gitee.com/ixinglan/parent-seata-tcc-demo.git)

  > 注意3个注解
  >
  > ```java
  > @LocalTCC 
  > 该注解需要添加到上⾯描述的接⼝上，表示实现该接⼝的类被 seata 来管理，seata 根据事务的状态，⾃动调⽤我们定义的⽅法，如果没问题则调⽤ Commit ⽅法，否则调⽤ Rollback ⽅法。
  > ```
  > ```java
  > @TwoPhaseBusinessAction 
  >     描述⼆阶段提交
  >     name: 为 tcc⽅法的 bean 名称，需要全局唯⼀，⼀般写⽅法名即可
  >     commitMethod: Commit⽅法的⽅法名
  >     rollbackMethod:Rollback⽅法的⽅法名
  > 
  > @BusinessActionContextParamete 
  >     该注解⽤来修饰 Try⽅法的⼊参，
  >     被修饰的⼊参可以在 Commit ⽅法和 Rollback ⽅法中通过
  >     BusinessActionContext 获取。
  > 
  > ```
  
  

### 2.2 TM端改造

Demo-bussiness 不用变即可, 

```java
@GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 6000, name = "sale")
```

> tips:
>
> 1. debug的时候可以把超时时间调大一点,因为事务结束或超时,则用到的seata中间表数据就清掉了
> 2. undo_log表在tcc模式下没用了
> 3. 所有有数据操作的都必须有try/commit/rollback的实现.

回滚效果:

![img_11](https://img.zhaojq.top/20260727091844894.png "img_11")

提交成功效果:

![img_12](https://img.zhaojq.top/20260727091845115.png "img_12")

> Tips: 感兴趣可以debug看看中间表的数据变化情况










