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

北城余情 提交于 2021-01-09 04:56:17

点击上方“方志朋”,选择“设为星标

回复”666“获取新整理的面试文章

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

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注册。

在启动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


   
   
    
      
  
     
     

热门内容:


最近面试BAT,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

本文分享自微信公众号 - 方志朋(walkingstory)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!