Backend Development 17 min read

Implementing TCC Transaction Mode with Seata: Concepts, Types, and Code Example

This article explains the TCC (Try‑Confirm‑Cancel) distributed transaction model, its three phases, three practical variants, and provides a complete Seata‑based Java implementation with code samples, exception handling strategies, and deployment tips for backend services.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Implementing TCC Transaction Mode with Seata: Concepts, Types, and Code Example

This article introduces the TCC (Try‑Confirm‑Cancel) transaction model, a two‑phase commit pattern widely used for flexible distributed transactions, and explains its core idea: each business operation must register a corresponding confirm and cancel (compensate) action.

What is TCC?

TCC consists of two stages. The first stage, Try , performs business checks and reserves resources (e.g., locks). The second stage decides, based on the Try result, whether to execute Confirm (commit) or Cancel (rollback).

TCC Phases

Try : business validation and resource reservation.

Confirm : executes the real business logic and releases locks.

Cancel : releases the reserved resources when the Try fails.

Example: E‑commerce Order

The article uses an order‑placement scenario with two services (inventory and order) to illustrate Try, Confirm, and Cancel steps, showing how inventory is frozen during Try and released or committed in later phases.

Three Practical TCC Variants

1. General‑purpose TCC

All participant services are synchronously invoked; suitable for short‑duration operations such as order, account, and inventory services in an e‑commerce system.

2. Asynchronous‑ensure TCC

Participant services are decoupled via a reliable message service; Confirm and Cancel are executed asynchronously, making it appropriate for low‑sensitivity scenarios like user registration or email sending.

3. Compensation‑type TCC

Participant services provide only Do and Compensate interfaces; the main service still decides the transaction outcome, but rollback is performed via compensation logic.

Seata Integration of TCC

Seata supports multiple transaction modes (AT, TCC, SAGA, XA). The article focuses on TCC implementation.

Demo Scenario

A simplified order service with inventory service is used. The global transaction is started with @GlobalTransactional and the business logic is split into Try, Confirm, and Cancel methods.

@GlobalTransactional
public Result
createOrder(Long productId, Long num, ...) {
    // 1. Reduce inventory
    reduceStorage();
    // 2. Create order
    saveOrder();
}

Try Method

@Transactional
public boolean try() {
    // Freeze inventory
    frozenStorage();
    // Create order with status 'pending'
    saveOrder();
    // Add idempotent marker
    IdempotentUtil.add(this.getClass().getName() + xid, System.currentTimeMillis());
    return true;
}

Confirm Method

@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 marker
    IdempotentUtil.remove(this.getClass().getName() + xid);
    return true;
}

Cancel Method

@Transactional
public boolean cancel() {
    // Record cancel status in transaction log to avoid hanging
    transactionLog.insert(xid, "cancel");
    // Idempotency and empty‑rollback protection
    if (IdempotentUtil.get(this.getClass().getName() + xid) == null) return true;
    // Rollback frozen inventory
    rollbackFrozen();
    // Delete the pending order
    delOrder();
    // Remove idempotent marker
    IdempotentUtil.remove(this.getClass().getName() + xid);
    return true;
}

Handling Common TCC Exceptions

The three typical problems are empty rollback, idempotency, and hanging. Solutions include maintaining a transaction‑status table and using an idempotent utility map to record the state of each global transaction.

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;

During Cancel, the status is set to "cancel"; before Try executes, the service checks this table to avoid processing a transaction that has already been cancelled, thus preventing hanging.

Other Configuration

The article briefly mentions integrating Nacos, Feign, and ensuring the Seata transaction group (tx‑service‑group) is correctly configured.

Conclusion

TCC provides a relatively simple yet powerful way to achieve distributed consistency; readers are encouraged to download the source code and try the implementation.

backendJavaMicroservicestccdistributed transactionsseata
Code Ape Tech Column
Written by

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

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.