Step‑by‑Step Guide to Building Distributed Transactions with Seata and Spring Cloud

This tutorial explains how to ensure data consistency across microservices by implementing distributed transactions with Seata, covering architecture, service implementation, configuration, two‑phase commit protocol, transaction modes, and debugging techniques for a complete end‑to‑end solution.

Java One
Java One
Java One
Step‑by‑Step Guide to Building Distributed Transactions with Seata and Spring Cloud

Why Distributed Transactions Matter

In a distributed system, data must stay consistent across multiple services; a transaction should either succeed completely or roll back entirely, preventing partial updates that could corrupt business logic.

What Is Seata?

Seata is an open‑source framework that provides high‑performance, easy‑to‑use distributed transaction services for microservice architectures. It originated inside Alibaba and was open‑sourced in 2019.

Core Components of Seata

Seata introduces three key roles:

RM (Resource Manager) : Manages branch transactions and reports status.

TM (Transaction Manager) : Defines the global transaction scope and controls commit/rollback.

TC (Transaction Coordinator) : Coordinates the commit or rollback of all branch transactions.

Project Structure

The example builds four microservices under a spring-cloud-demo project: seata-account: Handles account balance deduction. seata-order: Creates order records. seata-storage: Manages inventory deduction. seata-business: Orchestrates the purchase flow.

Database Design

Each service uses its own MySQL database with a single table:

Account Service : account_tbl(id, user_id, money) Order Service : order_tbl(id, user_id, commodity_code, count, money) Storage Service :

storage_tbl(id, commodity_code, count)

MyBatis Mappers and Entities

For each table a MyBatis mapper XML and a corresponding Java entity are provided. Example for the account service:

public class AccountTbl implements Serializable {
    private Integer id;
    private String userId;
    private Integer money;
}
<mapper namespace="com.greenbook.account.mapper.AccountTblMapper">
    <resultMap id="BaseResultMap" type="com.greenbook.account.bean.AccountTbl">
        <id property="id" column="id" jdbcType="INTEGER"/>
        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
        <result property="money" column="money" jdbcType="INTEGER"/>
    </resultMap>
    ...
    <update id="debit" parameterType="java.lang.String">
        UPDATE account_tbl SET money = money - #{money} WHERE user_id = #{userId}
    </update>
</mapper>

REST Controllers and Services

Each service exposes a simple REST endpoint and a service layer that uses MyBatis to perform database operations. Example for the account service:

@RestController
public class AccountController {
    @Autowired
    AccountService accountService;

    @GetMapping("/debit")
    public String debit(@RequestParam("userId") String userId,
                       @RequestParam("money") int money) {
        accountService.debit(userId, money);
        return "account debit success";
    }
}
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    AccountTblMapper accountTblMapper;

    @Transactional
    @Override
    public void debit(String userId, int money) {
        accountTblMapper.debit(userId, money);
    }
}

OpenFeign Clients

Business service calls other services via OpenFeign interfaces, e.g.:

@FeignClient(value = "seata-account")
public interface AccountFeignClient {
    @GetMapping("/debit")
    String debit(@RequestParam("userId") String userId,
                 @RequestParam("money") int money);
}

Configuration

All services share similar Maven dependencies (Spring Boot, Spring Cloud, MyBatis, MySQL driver) and a application.yml that configures Nacos discovery and the service name. The global transaction group is set to the default:

seata:
  tx-service-group: default_tx_group

A file.conf placed in src/main/resources tells each service how to locate the Seata TC:

service {
  vgroupMapping.default_tx_group = "default"
  default.grouplist = "127.0.0.1:8091"
  enableDegrade = false
  disableGlobalTransaction = false
}

Running Seata Server

Start a Seata 1.5 server with Docker:

docker run --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:1.5.0

Access the console at http://localhost:7091 (username/password: seata).

Two‑Phase Commit Protocol

Seata implements a two‑stage commit:

Phase 1 – Each branch transaction performs a local commit and writes an undo log.

Phase 2 – The TC decides to commit or roll back all branches.

The process is illustrated in the following diagram:

Two‑phase commit diagram
Two‑phase commit diagram

Transaction Modes

Seata supports four modes:

AT (Automatic Transaction)

Default mode where Seata automatically handles commit/rollback using undo logs. All branch transactions in the example have branchType=AT.

XA

Uses the database‑native XA protocol. To enable, set seata.data-source-proxy-mode=XA in the configuration. XA holds locks for the entire transaction, which can impact performance compared to AT.

TCC (Try‑Confirm‑Cancel)

Manual two‑phase protocol where developers implement prepare, commit, and rollback methods. Suitable for non‑database resources such as sending emails or SMS.

public interface TccActionOne {
    @TwoPhaseBusinessAction(name = "DubboTccActionOne", commitMethod = "commit", rollbackMethod = "rollback")
    boolean prepare(BusinessActionContext ctx, @BusinessActionContextParameter(paramName = "a") String a);
    boolean commit(BusinessActionContext ctx);
    boolean rollback(BusinessActionContext ctx);
}

Saga

Long‑running transaction model that uses asynchronous messages to trigger compensating actions when a step fails. Ideal for workflows with human approval or external interactions.

Saga workflow diagram
Saga workflow diagram

Debugging with Seata Console

Set breakpoints in the business service, then invoke the purchase API:

http://localhost:11000/purchase?userId=1&commodityCode=P0001&count=2

Observe the global transaction in the Seata console, view branch status ( Registered), global locks, and undo logs stored in the undo_log table of each database.

Seata console transaction view
Seata console transaction view

Summary

This guide demonstrates a complete end‑to‑end implementation of distributed transactions using Seata, Spring Cloud, MyBatis, and OpenFeign. It covers service design, database schema, code implementation, configuration, server deployment, transaction protocols, mode selection, and practical debugging, providing a solid foundation for building reliable microservice systems.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

microservicesSpring Clouddistributed transactionSeatatwo-phase commitAT modeXA Mode
Java One
Written by

Java One

Sharing common backend development knowledge.

0 followers
Reader feedback

How this landed with the community

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.