Backend Development 12 min read

How to Configure Seata with Nacos in Spring Boot: A Step‑by‑Step Guide

This guide walks through setting up Seata's configuration and registry centers using Nacos, creating the required config files, initializing the database, and implementing account and storage services in a Spring Boot micro‑service project, complete with code samples and verification steps.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How to Configure Seata with Nacos in Spring Boot: A Step‑by‑Step Guide

Environment

Spring Boot 2.3.11.RELEASE, Spring Cloud Hoxton.SR8, Spring Cloud Alibaba 2.2.5.RELEASE, Seata 1.3.0.

Prerequisite

Install and start a Nacos service.

Seata Configuration Center

The configuration center acts like a "wardrobe" that stores configuration files. Seata clients (TM, RM) and the Seata server (TC) read settings such as the global transaction switch and session storage mode from it. There is no functional difference between Seata's configuration center and Spring Cloud's configuration center; the latter only applies to its own components.

Seata Registry Center

The registry center is the "address book" of a micro‑service architecture, mapping service names to addresses. Seata clients discover the Seata server addresses through it. Seata's registry center works the same way as Dubbo or Spring Cloud's registry centers, but it is scoped to Seata itself.

Seata Service Configuration

Create a config.txt file under %SEATA_HOME% with the following content:

<code>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&amp;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=5000</code>

Execute the initialization script (downloaded from the provided URL) using Git Bash on Windows:

<code>sh nacos-config.sh -h &lt;nacos_ip&gt; -p &lt;nacos_port&gt; -g &lt;nacos_group&gt; -t &lt;namespace&gt; -u &lt;nacos_user&gt; -w &lt;nacos_password&gt;</code>

Database Initialization Scripts

<code>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;</code>

After completing the above steps, verify the Nacos configuration (see screenshots).

Project Structure

The project contains two sub‑modules:

dt‑account‑service (account module)

dt‑storage‑service (inventory module)

Parent Project Dependencies

<code>&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;com.alibaba.cloud&lt;/groupId&gt;
    &lt;artifactId&gt;spring-cloud-starter-alibaba-seata&lt;/artifactId&gt;
    &lt;exclusions&gt;
      &lt;exclusion&gt;
        &lt;groupId&gt;io.seata&lt;/groupId&gt;
        &lt;artifactId&gt;seata-all&lt;/artifactId&gt;
      &lt;/exclusion&gt;
    &lt;/exclusions&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;mysql&lt;/groupId&gt;
    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
    &lt;artifactId&gt;spring-cloud-starter-openfeign&lt;/artifactId&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;io.seata&lt;/groupId&gt;
    &lt;artifactId&gt;seata-all&lt;/artifactId&gt;
    &lt;version&gt;${seata.version}&lt;/version&gt;
  &lt;/dependency&gt;
&lt;/dependencies&gt;

&lt;dependencyManagement&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;com.alibaba.cloud&lt;/groupId&gt;
      &lt;artifactId&gt;spring-cloud-alibaba-dependencies&lt;/artifactId&gt;
      &lt;version&gt;${spring-cloud-alibaba.version}&lt;/version&gt;
      &lt;type&gt;pom&lt;/type&gt;
      &lt;scope&gt;import&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
      &lt;artifactId&gt;spring-cloud-dependencies&lt;/artifactId&gt;
      &lt;version&gt;${spring-cloud.version}&lt;/version&gt;
      &lt;type&gt;pom&lt;/type&gt;
      &lt;scope&gt;import&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/dependencyManagement&gt;</code>

Account Module Configuration

<code>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: nacos</code>

AccountService Implementation

<code>@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");
        }
    }
}</code>

When userId equals 1002 , an exception is thrown to test transaction rollback. Remember to add the @GlobalTransactional annotation.

Feign Client for Storage Service

<code>@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);
}</code>

Storage Module Configuration (similar to account)

StorageService Implementation

<code>@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);
    }
}</code>

Testing Procedure

Start Seata, Nacos, the account service, and the storage service, then check Nacos for registration.

Verify that both services appear in the registry.

After initializing the database, perform a normal request and observe data changes. When userId=1002 is used, the transaction rolls back, leaving the database unchanged.

Console outputs for the account and storage modules confirm the XID propagation and rollback behavior.

The final database state shows no changes, confirming that the distributed transaction was successfully rolled back.

All steps complete.

JavaMicroservicesNacosSpring Bootdistributed transactionseata
Spring Full-Stack Practical Cases
Written by

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.

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.