6

五分钟体验分布式事务框架Seata

 3 years ago
source link: https://www.fangzhipeng.com/architecture/2020/06/11/seata-test.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。本教程旨在为读者提供一个快速入门seata的案例,详细使用请参考官方案例和文档。

seata12.png

seata-server搭建

在seata中,事务管理器是单独的一个服务,无需读者做二次开发,开箱即用。下载地址https://github.com/seata/seata/releases 。本文案例中使用2.1.0这个版本。下载完成并解压后,需要对seata-server进行配置,需要配置conf目录下的file.conf和registry.conf。

其中file.conf是配置seata-server的数据存储方式,支持本地文档和数据库,本文直接使用本地文件存储。配置如下:


## transaction log store, only used in seata-server
store {
  ## store mode: file、db
  mode = "file"

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "mysql"
    password = "mysql"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

registry.conf是配置seata-server的注册中心的,本文案例注册到eureka上。

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "eureka"

  nacos {
    application = "seata-server"
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  
  ...
 }

业务代码初始化

官网下载代码,也可以到本文整理出来的案例,下载地址:https://github.com/forezp/distributed-lab/tree/master/seata-sample

下载完成后,项目工程的文件目录如下,一共有5个工程,分别为eureka(注册中心)、business(交易发生的服务)、storage(库存服务)、order(订单服务)、account(账户服务),其中seata-server和另外四个业务服务都需要向eureka注册。sql目录为初始化sql的脚本。项目的目录结构如下。

seata-sample
├── account
├── bussiness
├── eureka
├── order
├── pom.xml
├── sql
└── storage

初始化sql

在数据库中创建seata的数据库,并导入在sql目录下的数据库脚本。

在业务代码中引入seata的sdk后,需要配置file.conf和registry.conf,请查看源码中的代码。在application.properties中配置mysql的连接:

spring.cloud.alibaba.seata.tx-service-group=my_test_tx_group
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/seatatest?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

依次启动seata-server,euraka,business,storage,order,account工程。访问eureka的地址:http://localhost:8761/ ,可以见到服务都向eureka注册。

seata13.png

在启动business服务时,会向数据库插入以下的数据:

 @PostConstruct
    public void initData() {
        jdbcTemplate.update("delete from account_tbl");
        jdbcTemplate.update("delete from order_tbl");
        jdbcTemplate.update("delete from storage_tbl");
        jdbcTemplate.update("insert into account_tbl(user_id,money) values('U100000','10000') ");
        jdbcTemplate.update("insert into storage_tbl(commodity_code,count) values('C100000','200') ");
    }

seata官方已经将代码逻辑写好了,直接测试即可。

curl http://127.0.0.1:8084/purchase/commit

此接口代码逻辑如下:


 @RequestMapping(value = "/purchase/commit", produces = "application/json")
    public String purchaseCommit() {
        try {
            businessService.purchase("U100000", "C100000", 30);
        } catch (Exception exx) {
            return exx.getMessage();
        }
        return "全局事务提交";
    }

即买30个库存,当前库存、金额都够,所以交易正常进行。

完成后可以看到数据库中 account_tblid为1的money会减少 5,order_tbl中会新增一条记录,storage_tblid为1的count字段减少 1

2020-05-21 16:09:12.388 INFO [AsyncCommitting_1]io.seata.server.coordinator.DefaultCore.doGlobalCommit:240 -Committing global transaction is successfully done, xid = 10.66.40.141:8091:2012236512.

发生异常事务回滚

调用如下的接口:

curl http://127.0.0.1:8084/purchase/rollback

此接口代码逻辑如下:

@RequestMapping("/purchase/rollback")
    public String purchaseRollback() {
        try {
            businessService.purchase("U100000", "C100000", 99999);
        } catch (Exception exx) {
            return exx.getMessage();
        }
        return "全局事务提交";
    }

次接口先扣掉了库存,然后扣掉了钱,最后查询数据库,发现数据库的库存为负数,于是抛出异常,发生回滚,待完成后数据库中的数据没有发生变化,回滚成功。可见分布式事务回滚操作成功。

http://seata.io/zh-cn/docs/overview/what-is-seata.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK