How to Set Up Seata Distributed Transactions with Spring Boot, Nacos, and MySQL
This guide walks through configuring Seata’s registry and configuration centers with Nacos, setting up MySQL storage, defining service modules, writing transactional code with @GlobalTransactional, and verifying rollback behavior in a Spring Boot 2.3 microservice project.
Environment: springboot 2.3.11.RELEASE, spring cloud Hoxton.SR8, spring cloud alibaba 2.2.5.RELEASE, seata 1.3.0.
Prerequisite: Nacos service is installed and running.
Seata Registry and Configuration Center Overview
Configuration Center acts like a "wardrobe" that stores configuration files; Seata clients (TM, RM) and servers (TC) read global transaction switches and session storage mode from it. In principle, Seata’s configuration center is the same as Spring Cloud’s, but it only applies to Seata components.
Registry Center is the "address book" of a microservice architecture, recording service‑address mappings. Services register themselves here and discover others, e.g., Seata clients locate Seata servers. Seata’s registry works like Dubbo or Spring Cloud registries, but it is scoped to Seata itself.
Seata Service Configuration
1. Create config.txt under %SEATA_HOME% with the following content:
service.vgroupMapping.dt-group=default
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&serverTimezone=GMT%2B8
store.db.user=root
store.db.password=xxxxxx
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=50002. Execute the script by downloading it from the provided address.
On Windows, run the shell script with Git Bash:
sh nacos-config.sh -h <nacos_ip> -p <nacos_port> -g <nacos_group> -t <namespace> -u <nacos_user> -w <nacos_password>3. Initialize the database with the following SQL statements:
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `global_table` (
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `branch_table` (
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `lock_table` (
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;After completing the steps, check the Nacos configuration:
Project Structure
The project contains two sub‑modules: dt‑account‑service (user module) and dt‑storage‑service (inventory module).
Parent POM Dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>${seata.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>Account Module Configuration (application.yml)
spring:
cloud:
nacos:
password: nacos
username: nacos
discovery:
server-addr: 118.24.111.33:8848
namespace: ""
group: dt-group
---
seata:
tx-service-group: dt-group
registry:
type: nacos
nacos:
application: seata-server
group: dt-group
namespace: ""
server-addr: 118.24.111.33:8848
username: nacos
password: nacos
config:
type: nacos
nacos:
namespace: ""
group: dt-group
server-addr: 118.24.111.33:8848
username: nacos
password: nacosAccountService Implementation
@Service
public class AccountService {
private static final String ERROR_USER_ID = "1002";
@Resource
private AccountMapper accountMapper;
@Resource
private StorageFeignClient storageFeignClient;
@Transactional(rollbackFor = Exception.class)
@GlobalTransactional
public void debit(String userId, BigDecimal num, String commodityCode, int orderCount) {
System.out.println(RootContext.getXID());
accountMapper.updateAccount(num, userId);
storageFeignClient.deduct(commodityCode, orderCount);
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ERROR_USER_ID.equals(userId)) {
throw new RuntimeException("account branch exception");
}
}
}Note: The @GlobalTransactional annotation is required to enable Seata’s distributed transaction management.
Feign Client for Storage Service
@FeignClient(name = "storage-service", url = "127.0.0.1:8802")
public interface StorageFeignClient {
@GetMapping("/storage/deduct")
void deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
}Storage Module (Configuration similar to Account)
StorageService Implementation
@Service
public class StorageService {
@Resource
private StorageMapper storageMapper;
@Transactional
public void deduct(String commodityCode, int count) {
System.out.println(RootContext.getXID());
storageMapper.updateStorage(count, commodityCode);
}
}Testing the Distributed Transaction
Start Seata, Nacos, account service, and storage service, then access Nacos to verify registration.
Normal request shows data changes; when userId=1002 is used, an exception triggers a rollback, leaving the database unchanged.
Account and storage service consoles confirm no data persistence after the rollback.
Database tables show no changes, confirming successful transaction rollback.
Setup complete.
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.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.
