TCC 是支付场景里最常见的分布式事务方案之一。它把“扣款”拆成 Try、Confirm、Cancel 三个阶段,降低锁持有时间,并保留强一致性能力。

CAP 理论

分布式系统无法同时满足:

  • 一致性
  • 可用性
  • 分区容忍性

现实里分区容忍性几乎必选,因此在一致性与可用性之间做权衡。

2PC 简述

2PC 通过协调者控制提交与回滚,保证原子性。

优势:清晰、易实现。

缺点:同步阻塞、单点风险、故障下不一致。

TCC 适用场景

TCC 作用于服务层,不依赖底层存储或 RPC 框架。

核心价值:

  • 跨服务事务一致性
  • 锁时间短,吞吐更高
  • 支持二阶段异步化

TCC 接口设计

三类异常

  • 空回滚
  • 幂等
  • 悬挂(Cancel 先于 Try)

处理思路

Try:插入事务记录,确保可追踪,若已完成二阶段则拒绝。

Confirm:检查事务状态,重复提交直接返回。

Cancel:允许空回滚,但必须写入状态,阻止后续 Try。

TCC 优化

同库模式

分支事务记录落在业务库,不依赖独立 TC 库。

优点:简单、可靠。缺点:需要异步扫描未完成事务。

异步化

允许二阶段延迟执行,适合高峰期资金压力。

同库模式表设计

CREATE TABLE `transaction_tab_0000` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) unsigned NOT NULL,
  `transaction_id` bigint(20) unsigned NOT NULL,
  `transaction_type` tinyint(3) NOT NULL DEFAULT '0',
  `status` tinyint(3) NOT NULL,
  `amount` bigint(20) NOT NULL,
  `create_time` bigint(20) NOT NULL DEFAULT '0',
  `update_time` bigint(20) NOT NULL DEFAULT '0',
  `ext_biz` bigint(20) unsigned NOT NULL,
  `ext_order_no` varchar(256) NOT NULL,
  `extra_data` JSON,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_transaction_id` (`transaction_id`),
  UNIQUE KEY `uk_ext_index` (`ext_order_no`, `ext_biz`, `transaction_type`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `wallet_change_tab_0000` (
  `wallet_change_id` bigint(20) unsigned NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `transaction_id` bigint(20) unsigned NOT NULL,
  `wallet_id` bigint(20) unsigned NOT NULL,
  `wallet_type` int(10) unsigned NOT NULL,
  `balance_old` bigint(20) NOT NULL,
  `balance_new` bigint(20) NOT NULL,
  `create_time` bigint(20) unsigned NOT NULL,
  `extra_data` JSON,
  PRIMARY KEY (`wallet_change_id`),
  KEY `idx_transaction_id` (`transaction_id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `wallet_tab_0000` (
  `wallet_id` bigint(20) unsigned NOT NULL,
  `wallet_type` tinyint(3) unsigned NOT NULL,
  `user_id` bigint(20) unsigned NOT NULL,
  `balance` bigint(20) NOT NULL,
  `create_time` bigint(20) unsigned NOT NULL,
  `update_time` bigint(20) unsigned NOT NULL,
  `version` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`wallet_id`),
  UNIQUE KEY `uniq_user_id_wallet_type` (`user_id`, `wallet_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

交易状态与类型

交易状态:

  • tried
  • confirmed
  • canceled

交易类型:

  • Topup
  • Payment
  • Transfer
  • Withdrawal
  • Request

资金流示例

用户资金流:

  • Try:deposit → moneyout
  • Confirm:moneyout → settlement
  • Cancel:moneyout → deposit

中间账户资金流:

  • Try:settlement → moneyin
  • Confirm:moneyin → deposit
  • Cancel:moneyin → settlement

TCC 示例

Try

START TRANSACTION;
SELECT wallet FOR UPDATE WHERE uid=123;
INSERT transaction -- txn_type: payment, status: tried
INSERT wallet_change;
UPDATE wallet SET deposit = deposit - 100, moneyout = moneyout + 100 WHERE uid=user_id;
COMMIT;

Confirm

START TRANSACTION;
SELECT wallet FOR UPDATE WHERE uid=123;
UPDATE transaction SET status='confirmed' WHERE ...;
INSERT wallet_change;
UPDATE wallet SET moneyout = moneyout - 100, settlement = settlement + 100 WHERE uid=user_id;
COMMIT;

Cancel

START TRANSACTION;
SELECT wallet FOR UPDATE WHERE uid=123;
UPDATE transaction SET status='canceled' WHERE ...;
INSERT wallet_change;
UPDATE wallet SET moneyout = moneyout - 100, deposit = deposit + 100 WHERE uid=user_id;
COMMIT;

小结

TCC 是支付系统的“强一致性工具箱”。用它的关键不是接口,而是对异常场景的完整覆盖和对幂等的严格执行。