十三、Alibaba Seata分布式事务

一、分布式事务

1. 概念

  • 一个微服务对应一个数据库,某个业务需涉及不同微服务,即涉及多数据库;
  • 一个业务在完成的时候,多个数据库的操作需要符合事务的要求;
  • 每个微服务的事务性只能都本地事务保证,不同微服务的事务性需要分布式事务来保证;

2. Seata

  • Alibaba的开源式分布式事务解决方案;
  • Seata官网

二、Seata组件

1. 1+3套件

Transaction ID(XID):

  • 全局唯一的事务ID;

TC - 事务协调者:

  • 维护全局和分支事务的状态,驱动全局事务提交或回滚;
  • TC(Server端)为单独服务端部署;

TM - 事务管理器:

  • 定义全局事务的范围:开始全局事务、提交或回滚全局事务;

RM - 资源管理器:

  • 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
  • TM和RM(Client端)由业务系统集成。

三、Seata安装 (windows 0.9版本)

其实就是一个微服务,来保证分布式事务

1. 下载

# 地址:如果下载很慢,自己去网上找百度云盘的资源吧
https://github.com/seata/seata/releases/tag/v0.9.0

2.seata/conf/file.conf

service模块

  • service模块:修改group属性 ;
service {
  #vgroup->rgroup
  
  # service模块:修改自定义事务组的名称
  vgroup_mapping.my_test_tx_group = "shuzhan_group"
  
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

store模块

  • 存储模式,默认为file,修改为db;
store {
  ## store mode: file、db
  
  # 存储模式,默认为file,修改为db
  mode = "db"

  ## file store
  file {
    dir = "sessionStore"

    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }

数据库设置

  • 上面修改后的db存储数据的数据库地址;
## database store
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
	
	# 数据库地址
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://60.205.229.31:3307/seata"
    user = "root"
    password = "123456"
	
	
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }

3. 建数据库

  • 在上述配置的数据库中建立seata数据库,并执行对应的sql;
  • sql位置: seata\conf\db_store.sql;
  • 主要来保存事务的执行过程中的相关信息;

4. seata/conf/registry.conf

  • seata 的server端也是要注册到注册中心的;
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  
  # 默认为file,改成注册到nacos
  type = "nacos"

 # 注册的nacos的ip及端口 
  nacos {
    serverAddr = "120.79.28.20:9001"
    namespace = ""
    cluster = "default"
  }

5. 启动

  • 先启动nacos;
  • 再启动seata server: windows, bin/seata server

四、业务类数据库

  • 分别为三个数据库 seata_order, seata_storage, seata_account;

order建表sql

 CREATE TABLE `se_order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '表id',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `product_id` bigint(20) DEFAULT NULL COMMENT '产品id',
  `count` int(11) DEFAULT NULL COMMENT '数量',
  `money` decimal(11,0) DEFAULT NULL COMMENT '金额',
  `status` int(11) DEFAULT NULL COMMENT '订单状态(0为创建中,1为已完成)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

storage建表sql

CREATE TABLE `storage` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '表id',
  `product_id` bigint(20) DEFAULT NULL COMMENT '产品id',
  `total` int(10) DEFAULT NULL COMMENT '总库存',
  `used` int(10) DEFAULT NULL COMMENT '消耗库存',
  `leftover` int(10) DEFAULT NULL COMMENT '剩余库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

account建表sql

CREATE TABLE `account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '表主键',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `total` decimal(50,0) DEFAULT NULL COMMENT '总额度',
  `used` decimal(50,0) DEFAULT NULL COMMENT '已用额度',
  `leftover` decimal(50,0) DEFAULT NULL COMMENT '剩余额度',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

三个库的回滚表

  • 对应的sql在seata/conf/db_undo_log.sql;
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,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

五、三个微服务业务类代码

1. 订单微服务

pom.xml

   <dependencies>

        <!--seata的相关依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <!--里面自带的依赖为0.7.9-->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--尽量和服务端的版本保持一致-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>0.9.0</version>
        </dependency>
        
        <!--web模块,这两个一般绑定在一起-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!--nacos注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--openfeign服务调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--mybatis与springboot的整合-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--阿里巴巴的druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!--mysql数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--swagger依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

application.yaml

server:
  port: 9001

spring:
  application:
    name: day-dreamer-order

  # 数据源只要设置好,并不需要额外的配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://60.205.229.31:3307/seata_order
    username: root
    password: 123456


  # 服务注册的Nacos地址:用IP加宿主机端口,不用写http
  cloud:
    nacos:
      discovery:
        server-addr: 120.79.28.20:9001

    alibaba:
      seata:
        # 自定义事务组名称,
        #    需要和seata-server中的seata/conf/file.conf的service模块保持一致
        tx-service-group: shuzhan_group

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

mybatis:
  mapper-locations: classpath:com.day.dreamer.order.*.xml
  type-aliases-package: com.day.dreamer.order.domain

file.conf

  • 将上述seata-server中修改完的file.conf复制,保存在业务微服务中,修改自定义事务组的名称;
  • service部分,store部分,db部分
 service {
  #vgroup->rgroup
  
  # 修改自定义事务组的名称:shuzhan_group,这里为啥和seata-server端配置的不太一样
  vgroup_mapping.shuzhan_group = "default"
  
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}
store {
  ## store mode: file、db
  
  # 存储模式,默认为file,修改为db
  mode = "db"

  ## file store
  file {
    dir = "sessionStore"

    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }
db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
	
	# 数据库地址
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://60.205.229.31:3307/seata"
    user = "root"
    password = "123456"
	
	
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}

registry.conf

  • 将上面seata-server改好后的配置registry.conf文件,也复制在该工程中;
  • 没看懂这一步要干啥,seata_server中是为了把seata_server注册到注册中心,但微服务在application.yaml中已经注册过了啊;
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  
  # 默认为file,改成注册到nacos
  type = "nacos"

  nacos {
    serverAddr = "120.79.28.20:9001"
    namespace = ""
    cluster = "default"
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值