Implementation of Springboot dubbo fescar Ali Distributed Transaction

  • 2021-07-10 19:50:52
  • OfStack

Everyone can go under Ali distributed affairs by Baidu, so I won't talk about it here. Below is the Ali distributed transaction open source framework 1 some information, this article is springboot+dubbo+fescar integration.

Quick start

https://github.com/alibaba/fescar/wiki/Quick-Start

GIT Address

https://github.com/alibaba/fescar

1. sql


CREATE TABLE `undo_log` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `branch_id` bigint(20) NOT NULL,
 `xid` varchar(100) 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`),
 KEY `idx_unionkey` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8 ; 
 
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `commodity_code` varchar(255) DEFAULT NULL,
 `count` int(11) DEFAULT 0,
 PRIMARY KEY (`id`),
 UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `user_id` varchar(255) DEFAULT NULL,
 `commodity_code` varchar(255) DEFAULT NULL,
 `count` int(11) DEFAULT 0,
 `money` int(11) DEFAULT 0,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
 
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `user_id` varchar(255) DEFAULT NULL,
 `money` int(11) DEFAULT 0,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO `storage_tbl` VALUES ('1', 'C00321', '100'); 
INSERT INTO `account_tbl` VALUES ('1', 'U100001', '9999');

2. Download fescar-server and start

https://github.com/alibaba/fescar/releases

Decompression


sh fescar-server.sh 8091 /home/admin/fescar/data/

win operating system startup directly


fescar-server.bat

3. Download zookeeper and start it.

4. demo structure

It is divided into inventory micro-service storage, account micro-service account, order micro-service order and consumer purchase.

The purchase process is as follows: first call storage microservice to reduce inventory, and then call order microservice to update account balance and generate orders. Order micro-service order is also used as consumer account account micro-service, which is mainly used to update account balance.

5. The address of demo is as follows

https://github.com/TalkIsCheapGiveMeMoney/springboot-dubbo-fescar.git

6. Run storage microservice, account microservice, order microservice and purchase consumers in turn.

We simulate the exception when we create the order. The specific class is as follows


package com.hcsoc.order.service; 
import com.alibaba.fescar.core.context.RootContext;
import com.hcsoc.account.api.AccountService;
import com.hcsoc.order.api.OrderService;
import com.hcsoc.order.api.bean.Order;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
@Setter
public class OrderServiceImpl implements OrderService{
 
  private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class);
  @Autowired
  private AccountService accountService;
  @Autowired
  private JdbcTemplate jdbcTemplate;
 
 
  public Order create(String userId, String commodityCode, int orderCount) {
    LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
 
    //  Calculate the order amount 
    int orderMoney = calculate(commodityCode, orderCount);
 
    //  Deduct money from account balance 
    accountService.debit(userId, orderMoney);
 
    final Order order = new Order();
    order.userId = userId;
    order.commodityCode = commodityCode;
    order.count = orderCount;
    order.money = orderMoney;
    // Analog anomaly 
    Integer.parseInt("2u");
 
    KeyHolder keyHolder = new GeneratedKeyHolder();
 
    jdbcTemplate.update(new PreparedStatementCreator() {
 
      public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement pst = con.prepareStatement(
            "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
            PreparedStatement.RETURN_GENERATED_KEYS);
        pst.setObject(1, order.userId);
        pst.setObject(2, order.commodityCode);
        pst.setObject(3, order.count);
        pst.setObject(4, order.money);
        return pst;
      }
    }, keyHolder);
 
    order.id = keyHolder.getKey().longValue();
 
    LOGGER.info("Order Service End ... Created " + order);
 
    return order;
  }
 
  private int calculate(String commodityId, int orderCount) {
    return 200 * orderCount;
  }
}

Confirm the data in the database before the purchase order, so as to compare after purchase. The unit price of goods is 200.

We see the account number table of account_tbl, the account balance of user U100001 is 9999, the inventory table storage_tbl, and the commodity inventory is 100. There is no order data in the order table order_tbl.

Let's perform the purchase order operation,

Execute the following url

http://127.0.0.1:9094/purchase?userId=U100001 & commodityCode=C00321 & orderCount=4

userId user id, commodityCode commodity number, orderCount purchase quantity.

Go again and return the following data


{
  "timestamp": "2019-02-01T02:54:27.422+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "For input string: \"2u\"",
  "path": "/purchase"
}

Looking at the account number table of account_tbl mentioned above, the account balance of user U100001 is 9999, the inventory table storage_tbl and the commodity inventory is 100. There is no order data in the order table order_tbl. Indicates the success of distributed transactions.

We remove the simulated exception and perform the purchase operation again.

http://127.0.0.1:9094/purchase?userId=U100001 & commodityCode=C00321 & orderCount=5

We found that the inventory of goods changed from 100 to 95, the balance of users changed from 9999 to 8999, and an order number was generated. The unit price of goods mentioned earlier was 200, and the data was correct.

Other distributed transaction frameworks, such as TCC and byteTcc, need to operate idempotence. Those who know TCC and ByteTcc should know that the development workload is very large and the operation needs idempotence, while Ali's fescar does not need it at all and does not need so much development workload. I hope fescar will become more and more mature.


Related articles: