跨行转账:TCC解决银行间账户余额同步问题
订单支付:Try阶段预扣库存,Confirm阶段实际扣款
对账系统:批量交易的事务一致性保障
一、添加依赖
<!-- Maven 依赖 -->
<dependency>
<groupId>org.mengyun</groupId>
<artifactId>tcc-transaction-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.mengyun</groupId>
<artifactId>tcc-transaction-spring</artifactId>
<version>1.2.0</version>
</dependency>
二、SpringBoot配置
#application.yml
tcc:
transaction:
repository:
type: redis # 事务日志存储类型(支持JDBC、ZooKeeper等)
redis:
host: 127.0.0.1
port: 6379
recover:
cron: "0 */1 * * * ?" # 定时任务补偿间隔(默认1分钟)
三、TCC接口与实现
@Conpensable(
confirmMethod = "confirmTransfer",
cancelMethod = "cancelTransfer",
asyncConfirm = false //是否异步Confirm(高并发场景建议true)
)
public interface PaymentService{
@Transactional
boolean tryTransfer(
@BusinessActionContextParameter(paramName = "fromAccount") String fromAccount,
@BusinessActionContextParameter(paramName = "toAccount") String toAccount,
@BusinessActionContextParameter(paramName = "amount") BigDecimal amount
);
boolean confirmTransfer(BusinessActionContext context);
boolean canelTransfer(BusinessActionContext context);
}
@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
private AccountDao accountDao;
@Override
public boolean tryTransfer(String fromAccount, String toAccount, BigDecimal amount) {
// 1. Try阶段:资源预留(冻结余额)
Account account = accountDao.selectForUpdate(fromAccount);
if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException();
}
accountDao.freezeAmount(fromAccount, amount); // 生成冻结记录
// 2. 记录事务上下文(自动由框架处理)
return true;
}
@Override
public boolean confirmTransfer(BusinessActionContext context) {
// 3. Confirm阶段:实际扣款
String fromAccount = context.getActionContext("fromAccount");
BigDecimal amount = context.getActionContext("amount");
accountDao.decreaseBalance(fromAccount, amount);
accountDao.unfreezeAmount(fromAccount, amount);
return true;
}
@Override
public boolean cancelTransfer(BusinessActionContext context) {
// 4. Cancel阶段:释放冻结资金
String fromAccount = context.getActionContext("fromAccount");
BigDecimal amount = context.getActionContext("amount");
accountDao.unfreezeAmount(fromAccount, amount);
return true;
}
}
四、启动TCC事务
@Service
public class TransferFacade {
@Autowired
private PaymentService paymentService;
@Autowired
private TransactionRepository transactionRepository;
@Transactional
public void executeTransfer(String fromAccount, String toAccount, BigDecimal amount) {
// 1. 创建事务上下文
TransactionContext context = new TransactionContext();
context.setPropagated(true);
// 2. 执行Try阶段
boolean tryResult = paymentService.tryTransfer(fromAccount, toAccount, amount);
if (!tryResult) {
throw new TryPhaseException("Try阶段失败");
}
// 3. 模拟其他服务调用(如风控检查)
riskCheckService.validate(fromAccount, amount);
// 4. 事务自动提交(框架自动触发Confirm)
}
}