参考资料:
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服务原理与实战》
《B站 尚硅谷 SpringCloud 框架开发教程 周阳》
《Seata 中文官网》
《Seata GitHub 官网》
《Seata 官方示例》
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务;它提供了 AT、TCC、Saga 和 XA 事务模式,为开发者提供了一站式的分布式事务解决方案;
XID;XID 对应全局事务的管辖;XID 的全局提交或回滚决议;XID 下管辖的全部分支事务完成提交或回滚请求;
${SEATA_HOME}\bin\sessionStore\root.data 中,性能较高(file 类型不支持注册中心的动态发现和动态配置功能);globaltable、branchtable、lock_table;vgroup_mapping,它表示事务分组映射,是 Seata 的资源逻辑,类似于服务实例,它的主要作用是根据分组来获取 Seata Serve r的服务实例;txServiceGroup 参数,这个参数有如下几种赋值方式:
${spring.application.name}-seata-service-group;spring cloudalibaba.seata.tx-service-group 赋值;seata.tx-service-group 赋值;txServiceGroup 去指定位置(file.conf 或者远程配置中心)查找 service.vgroup_mapping.${txServiceGroup} 对应的配置值,该值代表TC集群(Seata Server)的名称;clusterName.grouplist;
Seata 安装的是 AT 模型中的 TC,为方便理解这里称为服务端;
Seata 作为一个事务中间件,有很多种部署安装方式,有安装包部署、源码部署和 Docker 部署,这里介绍前两种。版本选 1.4.2;

${SEATA_HOME}\conf\file.conf 文件,store.mode="db"。如下图所示:
${SEATA_HOME}\conf\file.conf 文件里的 db 模块为自己需要连接的 MySQL 地址;
${SEATA_HOME}\script/server/db/mysql.sql 文件;-- 判断数据库存在,存在再删除
DROP DATABASE IF EXISTS seata;
-- 创建数据库,判断不存在,再创建
CREATE DATABASE IF NOT EXISTS seata;
-- 使用数据库
USE seata;
-- 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_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- 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 = utf8;
-- 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),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
${SEATA_HOME}\conf\registry.conf 文件里的 registry.type,以及下面的注册中心地址信息;

${SEATA_HOME}/script/config-center/config.txt 文件里,该文件只在源码包里有,笔者是源码安装 Seata 时做的这步;${SEATA_HOME}\script\config-center\nacos 目录下执行以下 nacos-config.sh 脚本即可;
先启动 Nacos,再执行 ${SEATA_HOME}\bin\seata-server.bat 文件;
启动成功后能在 Nacos 服务器里能看见 Seata 服务;


mvm install 将项目安装到本地;Server.run() 方法即可;

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
Seata 在 1.0 后支持将 ${SEATA_HOME}/script/client/conf 目录下的两个配置文件 file.conf 和 registry.conf 写进 .yml 格式文件里了(1.0 版本前不支持);
.yml 格式的配置文件在 ${SEATA_HOME}script/client/spring 目录下;
需要修改 seata.tx-service-group 和 seata.service.vgroup-mapping 一致,配置中心、注册中心等;
另一种配置方法:
Seata 通过代理数据源的方式实现分支事务;MyBatis 和 JPA 都需要注入 io.seata.rm.datasource.DataSourceProxy, 不同的是,MyBatis 还需要额外注入 org.apache.ibatis.session.SqlSessionFactory;
MyBatis:
@Configuration
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceProxy);
return sqlSessionFactoryBean.getObject();
}
}
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
@GlobalTransactional 开启全局事务,Seata 会将事务的 xid 通过拦截器添加到调用其他服务的请求中,实现分布式事务;在业务流程中执行库存扣减操作的数据库操作时,Seata 会基于数据源代理对原执行的 SQL 进行解析(Seata 在 0.9.0 版本之后支持自动代理);
然后将业务数据在更新前后保存到 undo_log 日志表中,利用本地事务的 ACID 特性,把业务数据的更新和回滚日志写入同一个本地事务中进行提交;

tbl_repo 表中主键值等于 1 的记录的全局锁;UNDO_LOG 一并提交;AT 模式和 XA 最大的不同点:分支的本地事务可以在第一阶段提交完成后马上释放本地事务锁定的资源;AT 模式降低了锁的范围,从而提升了分布式事务的处理效率;
UNDO_LOG 日志即可。这也是和 XA 最大的不同点;
UNDO_LOG 日志;UNDO_LOG 中记录的数据镜像进行补偿;
UNDO_LOG 记录;UNDO_LOG 中的 afterImage 镜像数据与当前业务表中的数据进行比较,如果不同,说明数据被当前全局事务之外的动作做了修改,那么事务将不会回滚;UNDO_LOG中的 beforelmage 镜像数据和业务 SQL 的相关信息生成回滚语句并执行;一阶段本地事务提交前,需要确保先拿到全局锁;
拿不到全局锁 ,不能提交本地事务。
拿全局锁的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁;
举例:


因为整个过程全局锁在 tx1 结束前一直是被 tx1 持有的,所以不会发生脏写的问题;
SELECT FOR UPDATE 语句的代理;
SELECT FOR UPDATE 语句的执行会申请全局锁 ,如果全局锁被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试;
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复