Quick Start

Let’s begin with a Microservices example.

Use case

A business logic for user purchasing commodities. The whole business logic is powered by 3 microservices:

  • Storage service: deduct storage count on given commodity.
  • Order service: create order according to purchase request.
  • Account service: debit the balance of user’s account.

Architecture

Architecture

StorageService

  1. public interface StorageService {
  2. /**
  3. * deduct storage count
  4. */
  5. void deduct(String commodityCode, int count);
  6. }

OrderService

  1. public interface OrderService {
  2. /**
  3. * create order
  4. */
  5. Order create(String userId, String commodityCode, int orderCount);
  6. }

AccountService

  1. public interface AccountService {
  2. /**
  3. * debit balance of user's account
  4. */
  5. void debit(String userId, int money);
  6. }

Main business logic

  1. public class BusinessServiceImpl implements BusinessService {
  2. private StorageService storageService;
  3. private OrderService orderService;
  4. /**
  5. * purchase
  6. */
  7. public void purchase(String userId, String commodityCode, int orderCount) {
  8. storageService.deduct(commodityCode, orderCount);
  9. orderService.create(userId, commodityCode, orderCount);
  10. }
  11. }
  1. public class OrderServiceImpl implements OrderService {
  2. private OrderDAO orderDAO;
  3. private AccountService accountService;
  4. public Order create(String userId, String commodityCode, int orderCount) {
  5. int orderMoney = calculate(commodityCode, orderCount);
  6. accountService.debit(userId, orderMoney);
  7. Order order = new Order();
  8. order.userId = userId;
  9. order.commodityCode = commodityCode;
  10. order.count = orderCount;
  11. order.money = orderMoney;
  12. // INSERT INTO orders ...
  13. return orderDAO.insert(order);
  14. }
  15. }

Distributed Transaction Solution with SEATA

Quick Start - 图2

We just need an annotation @GlobalTransactional on business method:

  1. @GlobalTransactional
  2. public void purchase(String userId, String commodityCode, int orderCount) {
  3. ......
  4. }

Example powered by Dubbo + SEATA

Step 1: Setup database

  • Requirement: MySQL with InnoDB engine.

Note: In fact, there should be 3 database for the 3 services in the example use case. However, we can just create one database and configure 3 data sources for simple.

Modify Spring XML with the database URL/username/password you just created.

dubbo-account-service.xml dubbo-order-service.xml dubbo-storage-service.xml

  1. <property name="url" value="jdbc:mysql://x.x.x.x:3306/xxx" />
  2. <property name="username" value="xxx" />
  3. <property name="password" value="xxx" />

Step 2: Create UNDO_LOG table

UNDO_LOG table is required by SEATA AT mode. You can obtain the specified version of the undo log SQL script from github.

  1. CREATE TABLE IF NOT EXISTS `undo_log`
  2. (
  3. `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
  4. `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
  5. `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
  6. `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
  7. `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
  8. `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
  9. `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
  10. UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
  11. ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
  12. ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

Step 3: Create tables for example business

  1. DROP TABLE IF EXISTS `storage_tbl`;
  2. CREATE TABLE `storage_tbl` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `commodity_code` varchar(255) DEFAULT NULL,
  5. `count` int(11) DEFAULT 0,
  6. PRIMARY KEY (`id`),
  7. UNIQUE KEY (`commodity_code`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  9. DROP TABLE IF EXISTS `order_tbl`;
  10. CREATE TABLE `order_tbl` (
  11. `id` int(11) NOT NULL AUTO_INCREMENT,
  12. `user_id` varchar(255) DEFAULT NULL,
  13. `commodity_code` varchar(255) DEFAULT NULL,
  14. `count` int(11) DEFAULT 0,
  15. `money` int(11) DEFAULT 0,
  16. PRIMARY KEY (`id`)
  17. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  18. DROP TABLE IF EXISTS `account_tbl`;
  19. CREATE TABLE `account_tbl` (
  20. `id` int(11) NOT NULL AUTO_INCREMENT,
  21. `user_id` varchar(255) DEFAULT NULL,
  22. `money` int(11) DEFAULT 0,
  23. PRIMARY KEY (`id`)
  24. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Step 4: Start Server

  1. Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
  2. Options:
  3. --host, -h
  4. The address is expose to registration center and other service can access seata-server via this ip.
  5. Default: 0.0.0.0
  6. --port, -p
  7. The port to listen.
  8. Default: 8091
  9. --storeMode, -m
  10. log store mode : filedb
  11. Default: file
  12. --help
  13. e.g.
  14. sh seata-server.sh -p 8091 -h 127.0.0.1 -m file

Step 5: Run example

Go to samples repo: seata-samples/at-samples, and find a suitable dependency setup. Start Account, Storage, Order, Business services accordingly.