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.
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_groupA 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.0Access 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:
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.
Debugging with Seata Console
Set breakpoints in the business service, then invoke the purchase API:
http://localhost:11000/purchase?userId=1&commodityCode=P0001&count=2Observe 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.
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.
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.
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.
