Implementing TCC Transaction Mode with Seata: Concepts, Types, and Practical Code
This article explains the TCC (Try‑Confirm‑Cancel) transaction model, its three practical variants, common pitfalls such as empty rollbacks, idempotency and hanging, and provides step‑by‑step Java code examples for integrating Seata TCC into a Spring Cloud micro‑service order system.
What is TCC?
TCC (Try‑Confirm‑Cancel) is a two‑phase commit pattern where each business operation registers a confirm and a cancel action, enabling flexible distributed transactions.
TCC Phases
Try : resource check and reservation (e.g., lock inventory).
Confirm : execute the real business logic and release locks.
Cancel : roll back reserved resources when the try fails.
Three Practical TCC Types
1. General‑purpose TCC
All participant services are synchronously invoked; suitable for short‑duration operations such as order, account, and inventory services in e‑commerce.
2. Asynchronous‑Assurance TCC
The downstream service is decoupled via a reliable message queue; suitable for low‑time‑sensitivity tasks like email sending.
3. Compensation‑type TCC
Downstream services provide Do and Compensate interfaces; useful when rollback may need manual intervention.
Implementing TCC with Seata
Seata supports AT, TCC, SAGA, and XA modes. The following sections focus on the TCC implementation.
1. Demo Scenario
We use an e‑commerce order flow with only order and inventory services. The order service is the global transaction initiator.
@GlobalTransactional
public Result<Void> createOrder(Long productId, Long num, ...) {
// 1. Reduce inventory
reduceStorage();
// 2. Save order
saveOrder();
}The AT mode shown above suffers from long lock times and cannot span multiple applications, so we switch to TCC.
2. TCC Interface Definition
In the order‑boot module, an OrderTccService is created and annotated with @LocalTCC. The @TwoPhaseBusinessAction annotation marks the try method and specifies the confirm and cancel method names.
3. TCC Method Implementations
Try (resource reservation)
@Transactional
public boolean try() {
// Freeze inventory
frozenStorage();
// Create order with status "pending"
saveOrder();
// Record idempotent key (class + xid)
IdempotentUtil.add(this.getClass().getName() + xid, System.currentTimeMillis());
return true;
}Confirm (commit)
@Transactional
public boolean confirm() {
// Idempotency check
if (IdempotentUtil.get(this.getClass().getName() + xid) == null) return true;
// Release frozen inventory
cleanFrozen();
// Update order status to "completed"
updateOrder();
// Remove idempotent record
IdempotentUtil.remove(this.getClass().getName() + xid);
return true;
}Cancel (rollback)
@Transactional
public boolean cancel() {
// Record cancel status to prevent hanging
transactionLog.insert(xid, 3);
// Idempotency & empty‑rollback guard
if (IdempotentUtil.get(this.getClass().getName() + xid) == null) return true;
// Restore frozen inventory
rollbackFrozen();
// Delete the pending order
delOrder();
// Clean idempotent record
IdempotentUtil.remove(this.getClass().getName() + xid);
return true;
}4. Handling the Three TCC Exceptions
Common solutions involve a transaction‑status table ( transactional_record) that records the global XID and its current state (1‑try, 2‑commit, 3‑cancel). This table enables:
Idempotency: check the status before confirm/cancel.
Empty rollback: ensure cancel runs only after a successful try.
Hanging: prevent late‑arriving try after cancel.
CREATE TABLE `transactional_record` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`xid` varchar(100) NOT NULL,
`status` int(1) DEFAULT NULL COMMENT '1. try 2 commit 3 cancel',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;5. Order Business Method
@GlobalTransactional
public void placeOrder(Long productId, int quantity) {
orderTccService.try(); // triggers try, confirm, or cancel automatically
}6. Additional Configuration
Integrate Seata with Nacos for service discovery, configure Feign clients, and ensure the tx-service-group is set in the Seata configuration.
Conclusion
TCC provides a lightweight, two‑phase transaction alternative to AT, reducing lock time and improving performance for high‑throughput order scenarios. The article supplies the essential code, explains how to avoid empty rollbacks, idempotency issues, and hanging, and points readers to the full source on GitHub.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
