尚硅谷SpringCloud2020简单学习记录(个人用)138-148集(完结)

Seata

单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。

总之,一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题。

进入Seata Seata的介绍

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,其内部版本在阿里经济体内部一直扮演着应用架构层数据一致性的中间件角色,帮助经济体平稳的度过历年的双11,对上层业务进行了有力的技术支撑。

Seata术语

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

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

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

处理过程:

TM TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID

XID 在微服务调用链路的上下文中传播;

RM TC 注册分支事务,将其纳入 XID 对应全局事务的管辖;

TM TC 发起针对 XID 的全局提交或回滚决议;

TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

进入Releases · seata/seata · GitHub

下载seata-server-0.9.0.zip

解压之后,修改conf目录下的file.conf内容:

Service模块:

service {

  vgroup_mapping.my_test_tx_group = "fsp_tx_group"

  default.grouplist = "127.0.0.1:8091"

  enableDegrade = false

  disable = false

  max.commit.retry.timeout = "-1"

  max.rollback.retry.timeout = "-1"

}

Store模块:

## transaction log store

store {

  ## store mode: filedb

  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

  }

  ## 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://127.0.0.1:3306/seata"

    user = "root"

    password = "你自己密码"

    min-conn = 1

    max-conn = 3

    global.table = "global_table"

    branch.table = "branch_table"

    lock-table = "lock_table"

    query-limit = 100

  }

}

新建数据库seata,使用conf目录下的db_store.sql建表

修改conf目录下的registry.conf

registry {

  # file nacos eurekarediszkconsuletcd3sofa

  type = "nacos"

  nacos {

    serverAddr = "localhost:8848"

    namespace = ""

    cluster = "default"

  }

目的是:指明注册中心为nacos,及修改nacos连接信息

先启动nacos,再启动seataseatabin目录下启动seata-server.bat

一定要先启动nacos,再启动seata

分布式业务说明:

这里我们会创建三个服务,一个订单服务,一个库存服务,一个账户服务。

当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存,再通过远程调用账户服务来扣减用户账户里面的余额,最后在订单服务中修改订单状态为已完成。

该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题。

下订单→扣库存→减账户(余额)

创建三个数据库:

CREATE DATABASE seata_order;

CREATE DATABASE seata_storage;

CREATE DATABASE seata_account;

分别在三个数据库创建相应的表

CREATE TABLE t_order (

  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,

  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',

  `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',

  `count` INT(11) DEFAULT NULL COMMENT '数量',

  `money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',

  `status` INT(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完结'

) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

SELECT * FROM t_order;

=================================

CREATE TABLE t_storage (

 `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,

 `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',

 `total` INT(11) DEFAULT NULL COMMENT '总库存',

 `used` INT(11) DEFAULT NULL COMMENT '已用库存',

 `residue` INT(11) DEFAULT NULL COMMENT '剩余库存'

) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO seata_storage.t_storage(`id`, `product_id`, `total`, `used`, `residue`)

VALUES ('1', '1', '100', '0', '100');

SELECT * FROM t_storage;

==========================

CREATE TABLE t_account (

  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',

  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',

  `total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',

  `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',

  `residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'

) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO seata_account.t_account(`id`, `user_id`, `total`, `used`, `residue`)  VALUES ('1', '1', '1000', '0', '1000');

SELECT * FROM t_account;

按照上述三库分别建造对应的回滚日志表

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;

最终效果:

业务需求:

下订单→减库存→扣余额→改订单状态

按照视频创建seata-order-service2001seata-storage-service2002seata-account-service2003

分别启动项目,输入http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100

如无错误,可以看到数据库发生变化

尝试不加@GlobalTransactional,AccountServiceImpl添加超时等待,再次输入

http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100

可以看到库存和账户金额虽然扣了,但订单状态并没有设置为已经完成,没有从01。而且因为feign的重试机制,还可能重复扣款

添加@GlobalTransactional,下单之后看数据库,发现没有任何变化,之前的错误不再出现。

补充内容:

AT模式如何做到对业务无入侵

一阶段加载:

在一阶段,Seata 会拦截业务 SQL”

解析 SQL 语义,找到业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”

执行业务 SQL”更新业务数据,在业务数据更新之后,

其保存成“after image”,最后生成行锁。

以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

二阶段提交:

二阶段如是顺利提交的话,因为“业务 SQL”在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

二阶段回滚:

二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的业务 SQL”,还原业务数据。

回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比数据库当前业务数据 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。

以上为138-148集的内容,后两集为面试视频,所以算是正式完结了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
尚硅谷Java视频教程_SpringCloud视频教程 本套视频从面试题,到SpringCloud各种核心组件,到最终的微服务架构总结,帮助大家快速入门、上手并精通微服务框架SpringCloud。 课程中对比了 Dubbo 和 SpringCloud,并深入讲授SpringCloud核心组件Eureka、Ribbon、Feign、Hystrix、HystrixDashboard、Zuul、Config。除此之外,还通过整合SpringMVC+SpringBoot+Mybatis构建一个可用的基于SpringCloud的微服务工程将上述技术组件逐步落地,让大家看得懂做得出学得会。 00、尚硅谷_SpringBoot_源码、课件 01.尚硅谷_SpringCloud_前提概述 02.尚硅谷_SpringCloud_大纲概览 03.尚硅谷_SpringCloud_从面试题开始 04.尚硅谷_SpringCloud_微服务是什么 05.尚硅谷_SpringCloud_微服务是什么2 06.尚硅谷_SpringCloud_微服务与微服务架构 07.尚硅谷_SpringCloud_微服务优缺点 08.尚硅谷_SpringCloud_微服务技术栈有哪些 09.尚硅谷_SpringCloud_为什么选择SpringCloud作为微服务架构 10.尚硅谷_SpringCloud_SpringCloud是什么 11.尚硅谷_SpringCloud_SpringCloud_VS_SpringBoot区别对比 12.尚硅谷_SpringCloud_SpringCloud_VS_Dubbo区别对比 13.尚硅谷_SpringCloud_SpringCloud功能域和官网资料介绍 14.尚硅谷_SpringCloud_SpringCloud国内使用情况 15.尚硅谷_SpringCloud_Rest微服务案例-总体概述 16.尚硅谷_SpringCloud_Rest微服务案例-父工程构建步骤 17.尚硅谷_SpringCloud_Rest微服务案例-API公共模块和部门Entity步骤 18.尚硅谷_SpringCloud_Rest微服务案例-部门服务提供者 19.尚硅谷_SpringCloud_Rest微服务案例-部门服务消费者 20.尚硅谷_SpringCloud_Eureka是什么 21.尚硅谷_SpringCloud_EurekaServer服务注册中心建立 22.尚硅谷_SpringCloud_将已有的部门微服务注册进Eureka服务中心 23.尚硅谷_SpringCloud_微服务完善_主机映射名称修改 24.尚硅谷_SpringCloud_微服务完善_主机IP信息提示 25.尚硅谷_SpringCloud_微服务完善_info内容构建 26.尚硅谷_SpringCloud_Eureka自我保护机制介绍 27.尚硅谷_SpringCloud_Eure服务发现 28.尚硅谷_SpringCloud_Eureka集群配置 29.尚硅谷_SpringCloud_Eureka比Zookeeper好在哪里 30.尚硅谷_SpringCloud_Ribbon是什么 31.尚硅谷_SpringCloud_Ribbon配置初步 32.尚硅谷_SpringCloud_Ribbon负载均衡 33.尚硅谷_SpringCloud_Ribbon核心组件IRule 34.尚硅谷_SpringCloud_自定义Ribbo的负载均衡策略(上) 35.尚硅谷_SpringCloud_自定义Ribbo的负载均衡策略(下) 36.尚硅谷_SpringCloud_Feign是什么 37.尚硅谷_SpringCloud_Feign工程构建 38.尚硅谷_SpringCloud_Hystrix断路器是什么 39.尚硅谷_SpringCloud_服务熔断 40.尚硅谷_SpringCloud_服务降级 41.尚硅谷_SpringCloud_服务降级熔断小总结 42.尚硅谷_SpringCloud_豪猪hystrixDashboard 43.尚硅谷_SpringCloud_如何查看hystrixDashboard 44.尚硅谷_SpringCloud_Zuul是什么 45.尚硅谷_SpringCloud_Zuul路由基本配置 46.尚硅谷_SpringCloud_Zuul路由访问映射规则 47.尚硅谷_SpringCloud_Config分布式配置中心是什么 48.尚硅谷_SpringCloud_Config服务端与Github通信 49.尚硅谷_SpringCloud_Config客户端通过Config服务端获得Github上的配置 50.尚硅谷_SpringCloud_Config

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值