SpringCloud Alibaba之Seata分布式事务学习笔记(二)

简介: SpringCloud Alibaba之Seata分布式事务学习笔记(二)

2.2、采用file模式来集成seata服务


2.2.1、启动seata-server


服务端下载地址:seata-server 1.4.2,由于是外网下载太慢,可使用下面链接下载


链接:https://pan.baidu.com/s/1AqmcHZY9Op2IucG7rHbjOQ
提取码:bb6f


下载解压后的目录如下:



进入到bin目录之后,我们来进行输入命令执行其中bat工具,直接来启动服务就好(默认是file模式):



seata-server.bat -p 8868


指定在8868端口来进行执行,启动效果如下:



2.2.2、服务集成seata组件实现全局分布式事务



三个服务都进行集成seata依赖,主要配置步骤如下:


1、引入seata依赖:


<!--    引入seata依赖    -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>


2、配置文件来添加seata配置项,下面给出三个服务的不同配置项,下面需要特别注意的就是黄线的部分需要根据不同的服务名来进行配置:



seata-user-service:
seata:
  service:
    vgroup-mapping:
      # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
      # 这个很关键,一定要配置对,不然会找不到服务
      user-service-seata-service-group: default
    grouplist:
      default: localhost:8868


seata-book-service:


seata:
  service:
    vgroup-mapping:
        # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
        # 这个很关键,一定要配置对,不然会找不到服务
      book-service-seata-service-group: default
    grouplist:
      default: localhost:8868


seata-borrow-service:


seata:
  service:
    vgroup-mapping:
      # 这里需要对事务组做映射,默认的分组名为 应用名称-seata-service-group,将其映射到default集群
      # 这个很关键,一定要配置对,不然会找不到服务
      borrow-service-seata-service-group: default
    grouplist:
      default: localhost:8868


3、三个服务的启动器都去开启seata事务注解:


@EnableAutoDataSourceProxy //开启seata事务配置


4、在本地数据库中创建undo_log日志表


由于三个服务都使用的一个数据库seata-demo,所以我们直接在一个数据库中创建即可
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;


5、最终在我们要进行分布式事务的service方法中添加全局事务注解!也就是borrow-service服务中的borrow()方法:


@GlobalTransactional



2.2.3、测试


提前准备


首先将seata-server服务器启动。


接着启动我们的三个服务:在启动时向seata-server去进行注册



看下seata-server服务的控制台:可以看到确实三个服务已经注册成功了



开始测试


首先来进行测试:http://localhost:8082/borrow/1/2



第一次借阅是没有问题的,看下数据库:



再次来进行借阅下:



ok,此时再看下数据库的各个表:原本在book表中产生问题的数据在这里就没有再出现了,可以看到中间出现异常能够成功回滚了



debug

我们在修改、删除操作上进行debug:



看下undo_log表:



扣减步骤完成后执行下一步:



再次看下undo_log表:



其中包含一个全局唯一xid:全局事务就是根据这一条记录来进行回滚管理的!


2.3、采用nacos模式服务


对于项目中引入依赖以及添加注解相关操作间2.2.2中的配置步骤,这里不再做演示。


2.3.1、配置完整步骤


1、在nacos中创建一个命名空间seata



2、修改配置文件


registry.conf:
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sof
  type = "nacos"
  nacos {
    # 应用名固定为seata-server
    application = "seata-server"
    # 注册中心的地址
    serverAddr = "127.0.0.1:8848"
    # 默认
    group = "SEATA_GROUP"
    # 命名空间的id
    namespace = "c30eb1d8-8e49-4b5d-beca-b1bf9479e94a"
    # 默认
    cluster = "default"
    # 连接用户名与密码
    username = "nacos"
    password = "nacos"
  }
}
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "c30eb1d8-8e49-4b5d-beca-b1bf9479e94a"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}



3、下载develop包,执行其中的script中脚本来对nacos的配置中心中seata命名空间配置项进行初始化:


下载地址:seata开发包


链接:https://pan.baidu.com/s/1iiQphUPbvgcIyXcIjUcjZA
提取码:cbr2


进入到其中nacos目录下执行脚本,在windows中我们使用git工具来使用:



./nacos-config-interactive.sh



最终效果如下:



4、手动在命名空间seata中添加三个服务的配置项:



service.vgroupMapping.user-service-seata-service-group   SEATA_GROUP   default
service.vgroupMapping.book-service-seata-service-group  SEATA_GROUP  default
service.vgroupMapping.borrow-service-seata-service-group  SEATA_GROUP  default


5、在三个服务项目中的各个服务添加配置项(替换之前的file模式):


# 2、nacos模式
seata:
  # 注册
  registry:
    # 使用Nacos
    type: nacos
    nacos:
      # 使用Seata的命名空间,这样才能正确找到Seata服务,由于组使用的是SEATA_GROUP,配置默认值就是,就不用配了
      namespace: c30eb1d8-8e49-4b5d-beca-b1bf9479e94a
      username: nacos
      password: nacos
  # 配置
  config:
    type: nacos
    nacos:
      namespace: c30eb1d8-8e49-4b5d-beca-b1bf9479e94a
      username: nacos
      password: nacos


6、关于nacos-server的会话存储位置(默认是file)


此时注册和配置相关的会话都继承在Nacos中进行了


还可以配置一下事务会话信息的存储方式,默认是file类型,那么就会在运行目录下创建file_store目录,可以看下启动seata-server后创建的文件效果:



6.1、其实我们可以将其搬到数据库中存储,只需要修改一下配置即可,在seata的命名空间中进行修改配置内容如下:


1、修改两个配置:store.session.mode、``store.mode的值为db`

2、接着我们对数据库信息进行一下配置:

数据库驱动(8.0的需要修改):com.mysql.cj.jdbc.Driver

数据库URL:默认就是seata数据库就好。

数据库用户名密码:store.db.user、store.db.password

6.2、创建一个数据库【seata】:



-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(255),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('HandleAllSession', ' ', 0);


那么配置就已经完成了!


2.3.2、测试

前提准备


启动nacos服务、seata服务如下:



执行seata启动的命令:


seata-server.bat -p 8868



启动三个服务:



与此同时,可以看到在seata服务的控制台中你可以看到里面的服务注册信息:



测试


访问借阅地址:http://localhost:8082/borrow/1/2



再此访问,肯定在中途去判断是否该用户借阅了书阶段出现异常,进行回滚,我们只需要关注book表中的书籍借阅数量有没有-1的问题,其实就是看其有没有回滚:



看下数据库:



没有问题!


2.3.3、debug


在这里我们来进行打上断点:



看看seata数据库以及我们自己本身的数据库undo_log中的记录是否产生变化:


接着来了一个请求,我们看debug的目前阶段:



此时来看数据库的情况:


seata数据库:记录依次是红框从上往下







seata-demo中的undo_log表:



可以看到用户表中的xid是依赖于tc也就是seata-server来进行回滚的。

相关文章
|
2月前
|
Java 数据库
在Java中使用Seata框架实现分布式事务的详细步骤
通过以上步骤,利用 Seata 框架可以实现较为简单的分布式事务处理。在实际应用中,还需要根据具体业务需求进行更详细的配置和处理。同时,要注意处理各种异常情况,以确保分布式事务的正确执行。
|
5天前
|
Java 关系型数据库 数据库
微服务SpringCloud分布式事务之Seata
SpringCloud+SpringCloudAlibaba的Seata实现分布式事务,步骤超详细,附带视频教程
19 1
|
30天前
|
消息中间件 SQL 中间件
大厂都在用的分布式事务方案,Seata+RocketMQ带你打破10万QPS瓶颈
分布式事务涉及跨多个数据库或服务的操作,确保数据一致性。本地事务通过数据库直接支持ACID特性,而分布式事务则需解决跨服务协调难、高并发压力及性能与一致性权衡等问题。常见的解决方案包括两阶段提交(2PC)、Seata提供的AT和TCC模式、以及基于消息队列的最终一致性方案。这些方法各有优劣,适用于不同业务场景,选择合适的方案需综合考虑业务需求、系统规模和技术团队能力。
204 7
|
2月前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
93 6
|
2月前
|
数据库
如何在Seata框架中配置分布式事务的隔离级别?
总的来说,配置分布式事务的隔离级别是实现分布式事务管理的重要环节之一,需要认真对待和仔细调整,以满足业务的需求和性能要求。你还可以进一步深入研究和实践 Seata 框架的配置和使用,以更好地应对各种分布式事务场景的挑战。
50 6
|
2月前
|
消息中间件 运维 数据库
Seata框架和其他分布式事务框架有什么区别
Seata框架和其他分布式事务框架有什么区别
36 1
|
3月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
1月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
112 5
|
2月前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
74 8
|
2月前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
64 16