Cloud Native 16 min read

Quick Guide: Setting Up Nacos & Seata for Distributed Transactions

This tutorial walks through the rapid installation of Nacos in MySQL mode, the configuration of Seata 1.5.0, the creation of required database tables, the development of three micro‑services (stock, order, account) with Spring Cloud Alibaba, and the verification of global transaction rollback using a sample purchase scenario.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Quick Guide: Setting Up Nacos & Seata for Distributed Transactions

Environment Setup

Nacos Setup

Download the latest Nacos version and start it directly. The default console credentials are nacos/nacos. MySQL credentials are root/root and nacos/nacos.

Seata Setup

Use Seata version 1.5.0, which is a Spring Boot project. After downloading, modify application.yml (or resources/application.example.yml) to configure the registry, config center, and storage mode.

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata

seata:
  config:
    type: file
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      namespace:
      group: SEATA_GROUP
      cluster: default
      username: nacos
      password: nacos
  store:
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: root
      password: root
      min-conn: 5
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 100
      max-wait: 5000
security:
  secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
  tokenValidityInMilliseconds: 1800000
  ignore:
    urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

Create the Seata database and execute the following DDL scripts to build the required tables.

-- Global transaction table
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_status_gmt_modified` (`status`,`gmt_modified`),
  KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Branch table
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=utf8mb4;

-- Lock table
CREATE TABLE IF NOT EXISTS `lock_table` (
  `row_key` VARCHAR(128) NOT NULL,
  `xid` VARCHAR(128),
  `transaction_id` BIGINT,
  `branch_id` BIGINT NOT NULL,
  `resource_id` VARCHAR(256),
  `table_name` VARCHAR(32),
  `pk` VARCHAR(36),
  `status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
  `gmt_create` DATETIME,
  `gmt_modified` DATETIME,
  PRIMARY KEY (`row_key`),
  KEY `idx_status` (`status`),
  KEY `idx_branch_id` (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Distributed lock table
CREATE TABLE IF NOT EXISTS `distributed_lock` (
  `lock_key` CHAR(20) NOT NULL,
  `lock_value` VARCHAR(20) NOT NULL,
  `expire` BIGINT,
  PRIMARY KEY (`lock_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting','',0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting','',0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking','',0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck','',0);

Start Seata with seata-server. The console login uses seata/seata.

Project Setup

Business Background

The purchase flow involves three micro‑services:

Stock Service : Decrease inventory for a given product.

Order Service : Create an order based on the request.

Account Service : Deduct the user’s balance.

Architecture

Business Table Creation

-- t_account table
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `amount` double(14,2) DEFAULT '0.00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `t_account` VALUES ('1','1','4000.00');

-- t_order table
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_no` varchar(255) DEFAULT NULL,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT '0',
  `amount` double(14,2) DEFAULT '0.00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8;

-- t_stock table
DROP TABLE IF EXISTS `t_stock`;
CREATE TABLE `t_stock` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `t_stock` VALUES ('1','C201901140001','Water Cup','1000');

-- undo_log table (for Seata)
DROP TABLE IF EXISTS `undo_log`;
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,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS=1;

Service Creation

Business Service

Introduce dependencies in pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

Configure application.properties for the order service:

server.port=81
spring.application.name=order
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/seata_samples?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

Order creation endpoint:

@RequestMapping("/add")
public void add(String userId, String commodityCode, Integer count, BigDecimal amount) {
    Order order = new Order();
    order.setOrderNo(UUID.randomUUID().toString());
    order.setUserId(userId);
    order.setAmount(amount);
    order.setCommodityCode(commodityCode);
    order.setCount(count);
    orderService.save(order);
}

Aggregation Service

Define Feign clients for account, order, and stock services:

@FeignClient("account")
public interface AccountFeign {
    @RequestMapping("/account/reduce")
    void reduce(@RequestParam("userId") String userId, @RequestParam("amount") BigDecimal amount);
}

@FeignClient("order")
public interface OrderFeign {
    @RequestMapping("/order/add")
    void add(@RequestParam("userId") String userId,
             @RequestParam("commodityCode") String commodityCode,
             @RequestParam("count") Integer count,
             @RequestParam("amount") BigDecimal amount);
}

@FeignClient("stock")
public interface StockFeign {
    @RequestMapping("/stock/deduct")
    void deduct(@RequestParam("commodityCode") String commodityCode,
                @RequestParam("count") Integer count);
}

Global transaction method:

@Autowired
private OrderFeign orderFeign;
@Autowired
private StockFeign stockFeign;
@Autowired
private AccountFeign accountFeign;

@GlobalTransactional
@RequestMapping("/toOrder")
public void toOrder(String userId, String commodityCode, Integer count, BigDecimal amount) {
    accountFeign.reduce(userId, amount);
    stockFeign.deduct(commodityCode, count);
    orderFeign.add(userId, commodityCode, count, amount);
}

Testing & Verification

Initial data: account balance 4000, stock 1000. Simulate a purchase of 2000 items costing 4000. Expected results after the request:

Account balance insufficient → global rollback.

Stock insufficient → exception triggers rollback.

Business service rolls back the global transaction.

Account balance restored to 4000.

Invoke the API:

http://127.0.0.1/business/toOrder?userId=1&commodityCode=C201901140001&count=2000&amount=4000

Observe logs of account and stock services and verify that the database tables remain unchanged.

Precautions

Seata 1.5 uses MySQL driver 5.x; replace it with mysql-connector-java-8.xx.jar in the libs directory.

Ensure compatibility among Spring Boot, Spring Cloud, and Spring Cloud Alibaba versions (see the compatibility matrix image).

Check Druid and driver version compatibility via the Druid repository documentation.

Code Repository

https://gitee.com/codeWBG/springcloud_alibaba
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.

Nacosmysqldistributed-transactionSpring Cloud AlibabaSeata
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.