分布式事务及Seata 1.6.1案例

文章目录

  • 一、分布式事务
  • 二、什么时候需要用到分布式事务
  • 三、分布式理论
    • CAP定理
    • BASE理论
  • 四、分布式事务解决方案
    • 刚性事务
      • 2PC
      • 3PC
      • 2PC和3PC对比
    • 补偿事务
      • TCC
    • 基于消息队列的最终一致性
      • 本地消息表
      • 消息事务
      • MQ事务消息和本地消息表对比
    • 各方案常见使用场景总结
  • 五、Seata 1.6.1测试
    • 1.配置seata
      • 1.1下载seater-server 1.6.1版本
      • 1.2配置seater-server
    • 2.配置nacos
      • 2.1 新建namespace
      • 2.1 新建seata的seataServer.properties配置文件
    • 3.配置MYSQL
      • 3.1 新建配置表
      • 3.2 业务数据库添加undo_log表
    • 4.启动seata-server
    • 5.测试seata的AT模式

一、分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

二、什么时候需要用到分布式事务

就是指不是单个服务或者单个数据库架构下产生的事务,例如:

  • 跨数据源的分布式事务
  • 跨服务的分布式事务

三、分布式理论

CAP定理

在一个分布式系统中,以下三点特性无法同时满足,「鱼与熊掌不可兼得」

  • 一致性(C):在分布式系统中的所有数据备份,「在同一时刻是否拥有同样的值」 。(等同于所有节点访问同一份最新的数据副本)
  • 可用性(A):系统能够在任何时候处理请求并返回非错误响应,即系统对于用户请求是可用的。
  • 分区容错性(P):系统能够容忍网络中的分区故障,即网络中的节点之间的通信可能被延迟或丢失。

具体地讲在分布式系统中,在任何数据库设计中,一个Web应用「至多只能同时支持上面的两个属性」 。显然,任何横向扩展策略都要依赖于数据分区。因此,设计人员必须在一致性与可用性之间做出选择。

BASE理论

BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证 核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为 “柔性事务”。

  • 基本可用「Basically Available(基本可用)」:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。如,电商网站交易付款出 现问题了,商品依然可以正常浏览。
  • 软状态「Soft state(软状态)」:由于不要求强一致性,所以BASE允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用 性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。
  • 最终一致「Eventually consistent(最终一致性)」:最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变 为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。

事务有刚性事务和柔性事务之分。

刚性事务(如单数据库中的本地事务)完全遵循 ACID 规范,即数据库事务正确执行的四个基本要素:

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

柔性事务,主要就是只分布式事务了,柔性事务为了满足可用性、性能与降级服务的需要,降低一致性(Consistency)与隔离性(Isolation)的要求,遵守 BASE 理论:

  • 基本业务可用性(Basic Availability)
  • 柔性状态(Soft state)
  • 最终一致性(Eventual consistency)

四、分布式事务解决方案

分布式事务解决方案大致分为如下3种:

  • 刚性事务
    • 2PC
    • 3PC
  • 补偿事务
    • TCC
  • 基于消息队列的最终一致性
    • 本地消息表
    • 消息事务

刚性事务

2PC

2PC也就是两阶段提交:

  • 第一阶段:准备阶段
  • 第二阶段:提交阶段

第一阶段:

  • 协调者 向所有的 参与者 发送事务预处理请求,称之为Prepare,并开始等待各 参与者 的响应。
  • 各个 参与者 节点执行本地事务操作,但在执行完成后并不会commit数据库本地事务,而是先向 协调者 报告说:我准备好提交了Yes或者我没准备好弄no

第一阶段执行完后,会有两种可能。1、所有都返回Yes. 2、有一个或者多个返回No。

第二阶段:

  • 如果所有参与者都返回yes,那么协调者向所有参与者发送commit命令,参与者都本地commit,在完成提交之后释放整个事务执行期间占用的事务资源。
  • 如果其中有参与者返回no或者超时没有返回,则协调者向所有参与者发送rollback请求,也就是撤销,将本地事务回滚,不commit。

3PC

3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

第一阶段(CanCommit):

  • 事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
  • 响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No

第二阶段(PreCommit):

根据参与者返回的请求,来决定是否进入PreCommit

  • 假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
    1.发送预提交请求 发送一个prepare-commit请求,进入PreCommit状态
    2.事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
    3.响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

  • 假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
    1.发送中断请求 协调者向所有参与者发送abort请求。
    2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

第三阶段(DoCommit):

进行真正的事务提交

  • 执行提交
    1.发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
    2.事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
    3.响应反馈 事务提交完之后,向协调者发送Ack响应。
    4.完成事务 协调者接收到所有参与者的ack响应之后,完成事务。

  • 中断事务 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
    1.发送中断请求 协调者向所有参与者发送abort请求
    2.事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
    3.反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息
    4.中断事务 协调者接收到参与者反馈ACK消息之后,执行事务的中断。

2PC和3PC对比

  • 阻塞问题:2PC在第二阶段(提交阶段)可能会出现阻塞,因为协调者需要等待所有参与者的响应才能决定是否提交事务。这种阻塞可能导致整个系统的性能下降。3PC通过引入预提交阶段,可以在某些情况下减少阻塞问题,使得参与者可以在预提交阶段确认是否可以提交事务。

  • 可靠性和一致性:2PC和3PC都是刚性事务解决方案,强调事务的强一致性和可靠性。在2PC中,所有参与者在接收到准备请求后都将执行事务,并在接收到提交请求时进行事务的提交。在3PC中,预提交阶段可以使得参与者在准备阶段时就能够拒绝事务,从而增加了可靠性和灵活性。

  • 单点故障:2PC中存在单点故障问题,即协调者的故障可能导致整个事务无法完成。3PC通过引入预提交阶段来减少单点故障的影响,当协调者故障时,参与者可以根据预提交消息自行决策是否提交事务。

总的来说,3PC相对于2PC引入了预提交阶段,以减少阻塞问题和单点故障的影响,增加了系统的可靠性和灵活性。然而,3PC也带来了额外的复杂性和通信开销。在实际应用中,需要根据具体的场景和需求来选择2PC还是3PC作为分布式事务解决方案。

补偿事务

TCC

TCC分别是Try、Confirm、Cancle的简称。大致包含2个节点,一是Try,二是Confirm/Cancle。

  • Try 阶段(一阶段):尝试执行,完成所有业务检查(一致性), 预留必须业务资源(占库存)。
  • Confirm 阶段(二阶段):确认执行真正执行业务,不作任何业务检查,只使用 Try 阶段预留的业务资源,Confirm 操作满足需要满足幂等性,Confirm 执行失败后需要进行重试。
  • Cancel 阶段:取消执行,释放 Try 阶段预留的业务资源,Cancel 操作也需要满足幂等性。Cancel 阶段的异常和 Confirm 阶段异常处理方案基本上一致。

TCC的优缺点:
优点:

  • 灵活性:TCC允许开发人员在业务逻辑中显式地定义事务的尝试(Try)、确认(Confirm)和取消(Cancel)阶段。这种显式的编程模型使得开发人员可以更加精确地控制事务的行为,适应各种复杂的业务场景。

  • 高并发性:TCC的尝试阶段通常是在本地执行,不涉及资源锁定或网络通信。这使得尝试阶段可以以高并发的方式执行,提高了系统的吞吐量和性能。

  • 可扩展性:TCC对于分布式系统的扩展性较好。每个参与者负责自己的事务逻辑,可以独立地进行水平扩展,减少了对中心化事务协调器的依赖。

  • 容错性:TCC可以通过取消阶段来处理各种异常情况,如参与者失败、网络故障或超时。在出现异常时,可以执行取消操作,回滚之前的尝试操作,确保数据的一致性。

缺点:TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。

基于消息队列的最终一致性

本地消息表

分布式事务及Seata 1.6.1案例_第1张图片

发送消息方:

  • 需要有一个消息表,记录着消息状态相关信息。

  • 业务数据和消息表在同一个数据库,要保证它俩在同一个本地事务。

  • 在本地事务中处理完业务数据和写消息表操作后,通过写消息到 MQ 消息队列。

  • 消息会发到消息消费方,如果发送失败,即进行重试。

消息消费方:

  • 处理消息队列中的消息,完成自己的业务逻辑。

  • 如果本地事务处理成功,则表明已经处理成功了。

  • 如果本地事务处理失败,那么就会重试执行。

  • 如果是业务层面的失败,给消息生产方发送一个业务补偿消息,通知进行回滚等操作。

开发中使用的消息中间件并不支持事务消息的功能,那么本地消息表是一种不错的最终一致性解决方案

消息事务

分布式事务及Seata 1.6.1案例_第2张图片
1.事务发起方首先发送半消息到MQ;

2.MQ通知发送方消息发送成功;

3.在发送半消息成功后执行本地事务;

4.根据本地事务执行结果返回commit或者是rollback;

5.如果消息是rollback, MQ将丢弃该消息不投递;如果是commit,MQ将会消息发送给消息订阅方;

6.订阅方根据消息执行本地事务;

7.订阅方执行本地事务成功后再从MQ中将该消息标记为已消费;

8.如果执行本地事务过程中,执行端挂掉,或者超时,MQ服务器端将不停的询问producer来获取事务状态;

9.Consumer端的消费成功机制有MQ保证;

MQ事务消息和本地消息表对比

MQ事务消息:

需要MQ支持半消息机制或者类似特性,在重复投递上具有比较好的去重处理;

具有比较大的业务侵入性,需要业务方进行改造,提供对应的本地操作成功的回查功能;

DB本地消息表:

使用了数据库来存储事务消息,降低了对MQ的要求,但是增加了存储成本;

事务消息使用了异步投递,增大了消息重复投递的可能性;

各方案常见使用场景总结

  • 2PC/3PC:依赖于数据库,能够很好的提供强一致性和强事务性,但延迟比较高,比较适合传统的单体应用,在同一个方法中存在跨库操作的情况,不适合高并发和高性能要求的场景。
  • TCC:适用于执行时间确定且较短,实时性要求高,对数据一致性要求高,比如互联网金融企业最核心的三个服务:交易、支付、账务。
  • 本地消息表/MQ 事务:适用于事务中参与方支持操作幂等,对一致性要求不高,业务上能容忍数据不一致到一个人工检查周期,事务涉及的参与方、参与环节较少,业务上有对账/校验系统兜底。

五、Seata 1.6.1测试

参考:https://blog.csdn.net/weixin_40777510/article/details/129685726

1.配置seata

1.1下载seater-server 1.6.1版本

github地址:https://github.com/seata/seata/releases

1.2配置seater-server

conf目录下有一个application.example.yml,这是模板配置文件,还有一个application.yml,这是真正的配置文件,修改此文件,增加nacos的config和registry配置:

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: 29abe988-e6d6-4ca3-85e4-188e3b7e41dd
      group: DEFAULT_GROUP
      username: nacos
      password: nacos
      data-id: seataServer.properties
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: DEFAULT_GROUP
      namespace: 29abe988-e6d6-4ca3-85e4-188e3b7e41dd
      cluster: default
      username: nacos
      password: nacos
  store:
    # support: file 、 db 、 redis
    mode: file
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

注意:

  • seata.config.type 与seata.registry.type 都要修改为nacos
  • 修改config与registry中nacos的配置,其中namespace与group须提前在nacos中进行配置

2.配置nacos

2.1 新建namespace

新建namespace命名空间,需与上述seata-server的application.yml中配置一致

分布式事务及Seata 1.6.1案例_第3张图片

2.1 新建seata的seataServer.properties配置文件

在上述namespace下新建application.yml中seata.config.nacos.data-id提到的配置文件:seataServer.properties
分布式事务及Seata 1.6.1案例_第4张图片

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
# 此处的mygroup名字可以自定义,只修改这个值即可
service.vgroup_mapping.stock-service-group=default
service.vgroup_mapping.order-service-group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
# 默认为file,一定要改为db,我们自己的服务启动会连接不到seata
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
# 修改mysql的配置
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 指定seata的数据库,下面会提
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000


#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

注意:

  • 修改service.vgroupMapping.mygroup=default该值,其中mygroup可以自定义,后面我们自己的服务启动时,配置文件中需要指定该group。
  • 修改store.mode store.lock.mode store.session.mode这三个值为db,才能让seata连接到下面的数据库中。
  • 修改store.db配置项下的配置,连接到自己的数据库。
  • 该文件参数的具体作用参考官网:http://seata.io/zh-cn/docs/user/configurations.html
  • 该配置源文件存放在seata目录下:seata/script/config-center/config.txt

3.配置MYSQL

3.1 新建配置表

在seata数据库中新建查询,执行如下sql,sql文件存放在:seata/script/server/db/mysql.sql中

-- -------------------------------- 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(32),
    `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`),
    KEY `idx_xid` (`xid`)
) 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 ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

3.2 业务数据库添加undo_log表

-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
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;

4.启动seata-server

双击:seata-server.bat 启动服务

查看两件事:
1.seata-server是否注册进nacos中
2.访问http://127.0.0.1:7091/#/login 能否进入seata的webui,用户名与密码默认为seata
分布式事务及Seata 1.6.1案例_第5张图片

5.测试seata的AT模式

项目结构如下:
分布式事务及Seata 1.6.1案例_第6张图片

参考官网的版本信息:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

我用的是

  • seata1.6.1
  • Spring Cloud Alibaba 2021.0.5.0
  • Spring Boot 2.6.13
  • Nacos 2.2.0

父pom.xml

<properties>
   <java.version>1.8java.version>
   <spring-cloud-alibaba.version>2021.0.5.0spring-cloud-alibaba.version>
   <springboot.version>2.6.13springboot.version>
   <lombok.version>1.18.8lombok.version>

   <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
   <sikpTests>truesikpTests>
   <maven-source-plugin.version>3.0.1maven-source-plugin.version>
   <maven-surefire-plugin.version>2.22.1maven-surefire-plugin.version>
   <seata.version>1.6.1seata.version>
   <mybatis-plus-boot-starter.version>3.3.0mybatis-plus-boot-starter.version>
properties>

<dependencies>
   <dependency>
       <groupId>com.alibaba.cloudgroupId>
       <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
       <exclusions>
           <exclusion>
               <groupId>org.springframework.cloudgroupId>
               <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
           exclusion>
       exclusions>
   dependency>

   
   <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-loadbalancerartifactId>
       <version>3.1.1version>
   dependency>

   <dependency>
       <groupId>com.alibaba.cloudgroupId>
       <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
   dependency>

   
   <dependency>
       <groupId>com.alibaba.cloudgroupId>
       <artifactId>spring-cloud-starter-alibaba-seataartifactId>
       <version>${spring-cloud-alibaba.version}version>
       <exclusions>
           <exclusion>
               <groupId>io.seatagroupId>
               <artifactId>seata-spring-boot-starterartifactId>
           exclusion>
           <exclusion>
               <groupId>io.seatagroupId>
               <artifactId>seata-allartifactId>
           exclusion>
       exclusions>
   dependency>
   <dependency>
       <groupId>io.seatagroupId>
       <artifactId>seata-allartifactId>
       <version>${seata.version}version>
   dependency>
   
   <dependency>
       <groupId>io.seatagroupId>
       <artifactId>seata-spring-boot-starterartifactId>
       <version>1.6.1version>
   dependency>

   <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-bootstrapartifactId>
       <version>3.0.4version>
   dependency>

   <dependency>
       <groupId>org.springframework.bootgroupId>
       <artifactId>spring-boot-starter-webartifactId>
   dependency>

   <dependency>
       <groupId>org.projectlombokgroupId>
       <artifactId>lombokartifactId>
   dependency>

   
   <dependency>
       <groupId>com.baomidougroupId>
       <artifactId>mybatis-plus-boot-starterartifactId>
       <version>${mybatis-plus-boot-starter.version}version>
   dependency>
   

   <dependency>
       <groupId>mysqlgroupId>
       <artifactId>mysql-connector-javaartifactId>
   dependency>

   <dependency>
       <groupId>io.github.openfeigngroupId>
       <artifactId>feign-slf4jartifactId>
       <version>11.8version>
   dependency>

   
   <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-openfeignartifactId>
       <version>2.2.6.RELEASEversion>
   dependency>
dependencies>

<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-dependenciesartifactId>
           <version>${springboot.version}version>
           <type>pomtype>
           <scope>importscope>
       dependency>

       
       <dependency>
           <groupId>com.alibaba.cloudgroupId>
           <artifactId>spring-cloud-alibaba-dependenciesartifactId>
           <version>${spring-cloud-alibaba.version}version>
           <type>pomtype>
           <scope>importscope>
       dependency>

       <dependency>
           <groupId>org.projectlombokgroupId>
           <artifactId>lombokartifactId>
           <version>${lombok.version}version>
       dependency>

       <dependency>
           <groupId>mysqlgroupId>
           <artifactId>mysql-connector-javaartifactId>
           <version>8.0.28version>
       dependency>

   dependencies>

dependencyManagement>

<build>
   <plugins>
       <plugin>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-maven-pluginartifactId>
       plugin>
   plugins>
build>

stock和order的pom.xml一样

<properties>
	<java.version>1.8java.version>
	<spring-cloud.version>2021.0.5spring-cloud.version>
properties>

<dependencies>
dependencies>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-starter-openfeignartifactId>
		dependency>

		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-dependenciesartifactId>
			<version>${spring-cloud.version}version>
			<type>pomtype>
			<scope>importscope>
		dependency>
	dependencies>
dependencyManagement>

order的配置文件

spring.application.name=order-service
server.port=9091
# Nacos 注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.loadbalancer.ribbon.enabled: false
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
spring.cloud.alibaba.seata.tx-service-group=order-service-group
spring.seata.order-service-group=default
logging.level.io.seata=info
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/seata_order?allowMultiQueries=true
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

stock的配置文件

spring.application.name=stock-service
server.port=9092
# Nacos 注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
spring.cloud.alibaba.seata.tx-service-group=stock-service-group
spring.seata.stock-service-group=default
logging.level.io.seata=info
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/seata_stock?allowMultiQueries=true
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

参考官网的业务代码:https://github.com/seata/seata-samples/tree/master/springcloud-nacos-seata

启动项目测试:

浏览器输入:http://localhost:9091/order/placeOrder/commit,数据正常扣减

打上断点,可以查看seata往unlog中记录的数据
在这里插入图片描述

查看控制台日志,能看出是2PC模式

分布式事务及Seata 1.6.1案例_第7张图片

浏览器输入:http://localhost:9091/order/placeOrder/rollback,测试回滚

分布式事务及Seata 1.6.1案例_第8张图片

你可能感兴趣的:(分布式事务,seata,分布式事务,2PC,本地消息表,AT模式)