当前位置: 首页 > news >正文

【SpringCloud】 微服务分布式环境下的事务问题,seata大合集

目录

微服务分布式环境下的事务问题

分布式事务

本地事务

 BASE理论与强弱一致性

BASE理论

强弱一致性

常见分布式事务解决方案 - 2PC

常见分布式事务解决方案 - TCC

 常见分布式事务解决方案 - 最大努力通知

常见分布式事务解决方案 - 最终一致性

Seata介绍与术语

 Seata生命周期

Seata 数据表初始化

Docker安装配置Seata服务

拉取镜像:

运行seata:

创建自己的挂载目录,把seata的配置文件拷贝出来:

然后再移除容器,再次docker run

Seata 客户端依赖坐标引入与踩坑排雷

添加pom依赖

Seata 客户端全局事务配置与实现

客户端配置

添加全局事务注解

测试

全局异常 - Seata还会生效吗?

情况1:异常发生在服务发起方(调用方)

情况2:异常发生在服务被调方

思考

全局异常 - Seata手动回滚

手动回滚

思考: 我们到底要不要加全局异常的捕获?

借助消息队列操作事务的弱一致性(最终一致性)

那么如何保证MQ的一致性呢?

MQ最终一致性流程

最终一致性落地(1) - 异步解耦微服务

API中创建InitResumeMQConfig

授权服务

工作服务

测试

 最终一致性落地(2) - 存储本地消息

创建消息数据表

保存本地消息

测试运行

最终一致性落地(3) - 自定义事务管理器发送MQ消息

断点测试

最终一致性落地(4) - 确认并删除本地消息

模拟异常

测试


微服务分布式环境下的事务问题

目前在用户登录后调用初始化简历,其实这个过程是发生在两个不同的服务,本质上是在两个不同的分布式节点下进行的,这样的场景如果一旦简历服务发生异常,那么各自的事务是无法回滚的。(可以尝试在简历初始化的时候模拟一个除零异常)

分布式事务

举例电商中的场景经典的分布式事务使用场景:

三个链路,最后一个链路失败,之前的所有链路的事务是无法回滚的。因为每个服务自己的事务已经结束并且提交了,那么不同的节点是无法控制之前节点的事务的,所以事务是无法跨服务、无法跨分布式的,对于这样的事务,我们称之为分布式事务。

所以说,用户的一次请求会由多个不同的系统来协同完成,而请求的一次事务是涉及到了多个系统,这多个系统是分布式部署的,我们称之为分布式事务。

思考一下:如果数据库是多个,上述操作必定存在分布式事务。那么如果仅仅只有一个数据库,那么也会发生分布式事务吗?

本地事务

回顾一下本地事务。 事务浅白点讲就是一连串的动作可以组成一个工作单元,这个工作单元具有如下几个特征:

  • 原子性(Atomicity):工作单元的所有操作,要么全部成功,要么全部失败,如果有一部分失败,则其余成功的需要回滚。
  • 一致性(Consistency):数据的状态前后保持一致,或者说数据状态的转换姿势是一致的。比如我给你转账,我这边扣除100,你那边增加100,数据在这个过程中有增减,这个状态是始终一致的。
  • 隔离性(Isolation):如果多个事务同时正在进行中,事务是事务之间是相互隔离互不影响的,事务执行过程中发生的数据改变,仅仅只存在与该事务中,对外部是没有任何影响的。只有事务提交以后,才会被查询到最新的数据。
  • 持久性(Durability):数据操作执行完毕以后,这个数据的改变是永久存储起来的,即使电脑关机重启,数据依然存在。这个也称之为数据的持久化。 以上四点,俗称,事务的ACID特性。

本地事务是我们在进行单体应用架构时使用最多的一种数据库事务模式,由数据库来提供事务的支持,因为只有一个数据库,用户操作都是在一个工作单元中进行的,所以这也称之为本地事务。而且我们也都会借助数据库来完成事务的控制。

 BASE理论与强弱一致性

BASE理论

我们之前其实讲过了CAP定理,那么其实还有一个叫做BASE理论的玩意,这是对CAP的拓展。我们说过,现在主流的互联网项目,所采用的模式都是AP模式,也就是可用性和分区容错性,而一致性呢,我们可以采取一定的手段,让他来达到最终一致性。那么BASE理论呢,其实就是针对一致性来说的。如下:

  • 基本可用 Basically Available:分布式系统在出现故障出现异常的时候,可以允许损失一部分可用性,但是核心功能还是可以提供服务的。就像反浩克装甲那样,有些部件损坏了,但是机甲本身还是可用的,还可以正常打怪兽的。

    • 比如在高并发的时候,大流量涌入,那么系统的响应反馈实现可能会慢,本来搜索只需要几毫秒,现在可能要三、四秒,这是时间纬度可用性的降低。
    • 对于双11来说,我们平时下单成功会跳转到一个正常的订单页面,展示购买内容。而高并发的时候我们会做好兜底方案进行降级,一旦流量激增,那么部分页面可能就直接做一个简单提示了,很多查询页面你频繁刷新也不会显示,这是历年双11都会历经的情况。
  • 软状态 Soft State:这是分布式系统中允许存在的中间状态,这个中间状态不会影响整个系统的可用性。什么意思呢,一个数据,在不同的系统中,他可能存在多个副本,也就是不一致性,这个不一致性是可以被允许的,分布式节点在数据同步的过程其实就是不一致的。阿里的一些系统,也是这么规定允许的,哪怕数据存在不一致性,也必须保证数据库以及整个网站的可用性。因为不一致性是中间状态,会被修改,哪怕是bug,也可以被修复,而数据库或者系统一旦出现问题导致不可用,那么损失的就是用户以及钱。

  • 最终一致性 Enentual Consistency:这个是我们一直说的,我们并不要求数据在同一个时刻同一个工作单元内一致性,而是过一段时间,最终达到一致性,而这个一致性在业务上是可以被允许的。

强弱一致性

强一致性:必须保证ACID这四个特性。比如银行转账就是非常典型的例子,其实只要和前有关的,就必须保证强一致性,哪怕不可用,中断交易,也必须保证多方的数据是一致的,因为钱很重要,是经济稳定的根本。(对吧,咱们一下子高度又拔高了~)所以我有时候在atm上存钱其实会很慢,因为他要做好很多的把控,不能少你钱也不能多你钱,有时候也会很慢,登录几分钟,甚至最后一步出现错误会导致你重新存钱。上一节课提到的本地事务,在单体架构、单个服务中的事务,都是强事务,强一致性。

弱一致性:隔离性无所谓,实现的是最终一致性。我下了订单,也付钱了,这些操作都成功了,但是订单我现在查不到,可能要等10分钟以后才会有,这是典型的高并发案例把,在双11的时候也非常常见,这就是弱一致性。也是互联网的常用手段。而转账的时候,钱转了,对方查询要等10分钟以后才有,那双发岂不是要煎熬10分钟?尤其买房交易的时候,多难受啊对吧,所以金融类交易必须是强一致性。而分布式系统中往往都是弱一致性。

常见分布式事务解决方案 - 2PC

2PC,也叫做2阶段协议提交,把咱们的分布式事务拆分为2个阶段。这两个阶段是由协调者和参与者组成的。

如下图:

  • 协调者:是一个统一的管理者,用于管理参与者的,可以说他就是事务管理器,是负责整个全局事务提交和回滚的。
  • 参与者:一般指数据库,或者说各自的单节点服务,参与者的事务由自己管理提交或回滚。

处理过程:

  • 阶段1:就是P,prepare。协调者通知并询问参与者是否OK,如果都OK则进行阶段2,此阶段只准备,不提交。
  • 阶段2:就是C,commit。参与者告知协调者没问题了,那么此时发起指令让大家去提交。如果确认收到只要有一方为no,那么表示失败,则事务管理器会进行回退操作;如果为yes,则事务管理器则提交事务完毕。

举例:赛道短跑比赛,吹口哨的会说,预备。。。这是第一个阶段,让大家就绪。再说跑。。。,这个时候大家都跑了,如果不预备,可能有有没准备好导致滑到,那么大家又得重新来。

简单来说,2pc就是2个步骤,先准备,后提交,哪个步骤确认失败都会进行回滚。

需要注意,2PC的性能不好,因为事务资源管理器会占用大量资源,互联网高并发项目肯定不能用,金融类的没关系。

常见分布式事务解决方案 - TCC

TCC就是事务补偿机制,try、confirm、cancel。这整个闭环是在业务层自己进行控制的。

  • try:检查资源,预留资源,比如扣库存的时候需要检查一下是否符合条件,然后锁住扣除的库存数量,账户余额够不够,够的话则需要冻结一部分。其实也就是为了后续的数据库操作提前做好准备工作。
  • confirm:去执行各个节点的入库操作,比如:创建订单、扣库存、扣余额等,也就是对try阶段中的预留资源进行正式的数据处理。
  • cancel:很明显,就是取消操作,对try阶段中的预留资源进行资源释放(回退)。 对于tcc而言,并没有所谓的事务回滚,而是通过我们自己手动进行数据的回退,也就是对try阶段的数据,手动处理,比如删除订单,增加库存。这是一种补偿机制。

使用tcc:

  • 优点:可以保证数据一致性,业务层可以自由控制事务,灵活性较高。
  • 缺点:开发成本维护成本较高,工作量偏多,可能因为一些bug导致资损。每个事务操作都需要实现 try/confirm/cancel 的相关方法,也就是这几个方法都是自己要手动实现的。此外由于不是通过事务控制数据的回滚,所以幂等性需要保证,也就是不管调用请求多少次,数据结果都是一致的,不能因为请求两次,就对数据库进行两次的数据操作。

相对来说,tcc是柔性事务,他是最终一致性。而刚性事务呢,就是必须满足ACID各项特性,也就是强一致性。互联网项目中,使用tcc的还是偏多的。

 常见分布式事务解决方案 - 最大努力通知

最大努力通知,这种方案一般用于和第三方的对接,比如微信支付、支付宝支付。另外有一些兄弟公司或者同公司的兄弟项目,也会使用这种方式。在我们进行支付接口调用完毕后,最终到底支付失败还是成功,对方会给我们一个通知,这个通知是多次的,定时每隔几秒发一次通知,一般来说是8次,比如1s/10s/30s/60s/5m/10m/30m/……,多次发通知的目的其实就是让我们自己去对接过做好核对,不管成功还是失败都要做。这种方式的原理其实也就是通过mq异步发通知。如果是成功的通知,我们是否处理也无所谓,如果处理,则需要返回响应,说我知道了,你别再发了,对方则中断通知;如果失败,那么自己就需要做好失败的相关代码逻辑。(这块内容在后续对接微信的时候,也会有)

除此以外,是否成功失败的状态,第三方也提供了一个专门的接口,提供给我们查询,以防8次通知后 对方不发了,但是我们还没来得及处理,这个时候就需要我们自己手动主动去查询结果,最终再处理自己的成功或失败的业务。

所以说最大努力通知其实也可以称之为数据定期校对。最大努力,其实也就是事务发起方使劲浑身解数(比如:重试,轮训。。等操作)对数据进行校验,保证两头都是没问题的。我们自己公司也有类似的场景,就是数据回盘,我们会写到txt文本文件,然后和第三方公司接口的数据进行比对,如果不对,则该笔订单撤销。

常见分布式事务解决方案 - 最终一致性

最终一致性呢,就是把本地的多个事务进行拆分,拆分为各个子事务,中间使用消息队列进行异步协调来完成。

从图中可以看到,这里面并不像2pc和tcc那样,是有事务管理器的,采用消息队列并不需要TM。

所以对于这样的一种情况来说,最终必定是成功的,因为如果不成功,消息数据一直存在与数据库中,哪怕服务参与者无法处理该业务,一直抛出异常,或者宕机死机,那么再修复完毕以后,重新读取消息表,则还是依然可以处理数据的。如此一来,多端的服务最终都会达到一致性,虽然中间会有一定的延迟时间间隔,但是最终一致性的目的是可以达到的。

  • 优点:借助MQ异步解耦的特性,可以提高整体性能,开发成本相对比TCC要少一些。
  • 缺点:由于存在本地消息表,所以会对消息表进行频繁的读写,如此造成一定的数据库压力以及数据库资源的开销。

Seata介绍与术语

前面聊了一些常见的分布式事务方案,接下来我们所主要实现的是通过微服务的阿里组件,seata来实现微服务领域中的分布式事务。

https://github.com/seata/seata https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

  • AT模式(Auto Transcation)是阿里首推的,因为对代码是零侵入的,使用起来很方便。

  • TC:班主任,某某学生成绩下滑,学校里打架,则通知家长回家好好教育(驱动回滚);学生成绩表现各方面都不错,则也告知家长在校的情况(驱动提交)。所以TC是协调全局的。
  • TM:班长,主要做事的,发起人,带头人,哪些学生作业做的不好,则下发命令让他们重做或者修改错题。(全局事务的开启、回滚、提交)
  • RM:学生,做好自己的本质工作,完成每天的作业(本地事务)。班长既是TM又是RM,因为他也是学生的一员啊。

业务流程

  1. TM告知TC,准备开启一个全局事务,则TC将会开启一个全局事务
  2. 每个RM会向TC进行注册分支事务,并且会向TC汇报事务状态(成功或失败)
  3. 如果某个RM执行失败,则会通知TC说我自己的事务失败了,需要回滚,这个时候TC向TM下达命令,把各自的分支事务去回滚即可 所以,TC、TM、RM 看似分割,实则藕断丝连,相互紧密联系

 Seata生命周期

  1. 每个微服务都有各自的本地事务,完成后调用下一个微服务。
  2. TM事务管理器请求TC协调者开始一个全局事务,TC会生成一个全局事务的唯一字符串:XID。
  3. XID会在微服务链路中进行传播。
  4. 全局事务是由分支事务构成的,RM把本地事务作为分支事务注册到TC。
  5. TM请求TC提交或者回滚对应XID的全局事务。
  6. TC驱动XID全局事务下的所有分支事务进行提交或回滚。

这个XID,作为全局事务ID是贯穿整个分布式事务的过程的。 我们通过实例再来阐述一下流程: TC:项目经理 TM:产品经理 RM:程序员

  1. TM产品经理跟要做一个新需求,需要向TC项目经理提,这个新需求的工单ID为XID。
  2. 新需求的工单ID是一个大的单号,需要切分给多个技术团队去做,最终融合后就是这个大需求。整体来说所有的技术团队程序员都是为了这个XID共同去协作开发的。
  3. 每个程序员RM在做各自任务的时候,需要向TC项目经理汇报,你不汇报,项目经理TC无法知道你的任务进度,你的任务状态与进展。
  4. TM产品经理觉得当前的需求开发都没问题,验证通过,可以提交上生产了,那么他会想TC项目经理提出申请。
  5. 或者说,这个TM产品经理,突然觉得这个需求没有任何意义,那就不做了吧,于是也需要向TC项目经理提出回滚,不再执行了。
  6. 不管提交还是回滚,TC项目经理需要告知每个RM程序员,让他们把自己手头的任务提交或者回滚。

从上面看的出来啊,这个TM产品经理就是搞事情的啊,做也是你,不做也是你。

Seata 数据表初始化

选择我们所需要的版本

初始化sql脚本: https://github.com/seata/seata/blob/1.5.2/script/server/db/mysql.sql https://github.com/seata/seata/blob/1.5.2/script/client/at/db/mysql.sql

创建seata数据库,并且运行脚本,如下:

需要注意,undo_log这张表是属于业务库的,我们需要放入自己的数据库里作为客户端表。因为我们只有一个业务库,所以放一份。如果你有多个数据库对应到自己的微服务,则每一个库都需要放这张表。

这些表我们可以不用理会,是seata服务去进行使用的。

Docker安装配置Seata服务

拉取镜像:

docker pull seataio/seata-server:1.5.2

运行seata:

docker run \
--name seata-server \
-p 8091:8091 \
-p 7091:7091 \
-d seataio/seata-server:1.5.2

创建自己的挂载目录,把seata的配置文件拷贝出来:

mkdir /home/seata/resources -p
进入容器内部:
docker exec -it seata-server sh
这是配置文件列表:(早期会有两个配置文件,新版本里没有了,使用的是yml配置文件)

docker cp seata-server:/seata-server/resources /home/seata

修改配置文件application.yml: 如下,这段配置可以直接从示例example中复制过来

以上分别是配置注册中心,配置中心,以及数据库存储配置

然后再移除容器,再次docker run

docker stop seata-server
docker rm seata-server

docker run \
--name seata-server \
-p 8091:8091 \
-p 7091:7091 \
-v /home/seata/resources:/seata-server/resources \
-d seataio/seata-server:1.5.2
 

为啥这么操作呢?为啥不一开始直接挂载呢,还少了一个步骤?因为我们需要他的配置文件,如果直接挂载,配置文件目录是为空的,需要重新下载源码包,再解压缩复制,步骤比较繁琐。

打开Nacos,检查结果:

如此安装配置成功!

Seata 客户端依赖坐标引入与踩坑排雷

添加pom依赖

Seata 服务端配置好以后,还需要再业务端,也就是咱们微服务节点里去进行配置。

api子工程pom中引入依赖,需要注意版本匹配:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><exclusion><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId></exclusion></exclusions>
</dependency><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.5.2</version>
</dependency>

需要注意,如果不排除,那么自带的seata版本是老版本,如此咱们在seata服务端的配置就失效了,因为版本不同配置方式已经更改了。

此处部分idea可能存在问,也就是以来的RM微服务端并没有覆盖原来的seata版本,如此会有问题,则需要在各自微服务的pom中添加如下,也就是再次覆盖:

<dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.5.2</version>
</dependency>

Seata 客户端全局事务配置与实现

客户端配置

配置本地事务所在微服务的seata配置,这两个文件一致即可。

添加全局事务注解

测试

重新运行接口,数据库没有数据,说明回滚成功

如果用的早期老版本 1.4 之前的,那么数据库是mysql8的话,datatime会有序列化问题,一定要注意,如果你现在用老版本,那么建议用mysql5或者mariadb。因为1.5里的jackson序列化支持对datatime的解析了。一定要注意。 此外。1.5和1.4的配置文件也完全不一样,有的同学安装1.4的方式安装1.5那肯定是不行的,会有坑。

全局异常 - Seata还会生效吗?

很多时候,我们会有一些全局异常的捕获,但是这个时候,全局事务还会不会生效。

我们来测试如下几种情况:

情况1:异常发生在服务发起方(调用方)

这种情况和之前的一样,并没有改动代码。

结果你会发现全局事务回滚了。

情况2:异常发生在服务被调方

这个时候,再次运行,观察数据库,我们发现数据新增了,导致两边不一致,如此分布式事务失效了,如下:

结果:用户数据新增了,简历数据由于异常本地回滚了。所以,全局事务没有触发,导致两边不一致。

原因分析:因为全局异常捕获了,被调方返回的是一个正常的响应数据,是经过处理的,所以发起方或者说seata就任务当前的远程调用是正常的,所以最终显示事务提交的信息,而不是会进行回滚。

思考

所以大家思考一下,我们要不要添加全局异常的捕获?又或者说,我们一定要添加全局异常的捕获并且要实现分布式事务回滚,怎么办?大家课后思考一下。

全局异常 - Seata手动回滚

手动回滚

创建切面:

创建全局事务

捕获到异常后回滚:

被调方也需要回滚:

运行结果:

回滚成功

思考: 我们到底要不要加全局异常的捕获?

我们现在的异常被全局捕获并且被统一处理,这种情况之下,我们会返回一个更加人性化的信息给到前端用户去看。按照我们以前的思路的确是这样。但是,我们现在是微服务的调用,这些优雅的包装信息给调用方,也就是服务的发起方来查看其实没有太大的意义,所以这个全局异常再这样的情况之下可以省去,是没有必要的。

借助消息队列操作事务的弱一致性(最终一致性)

我们现在所操作分布式事务的场景其实并不是金融案例。仔细想一想,用户注册完毕,对于一份空的简历而言,其实可有可无的,他们之间并没有像转账那样有强关联性。所以,我们这里完全可以通过mq来解耦,只要mq投递成功,那么后续操作无所谓的。所以此处我们完全可以使用mq来解耦。

只不过,解耦操作完毕以后,我们需要保证消息前后的一致性即可。所以这样的场景,我们也称之为最终一致性。

那么如何保证MQ的一致性呢?

  • 可以用MQ的事务特性,完全可以,他的原理也是2PC,但是,使用的话性能很差,这个之前就有提过,高并发的时候是不建议使用的。
  • 消息和数据库是两个完全不一样的东西,存储介质也不一样,所以事务性必定无法保证的,所以,我们可以把消息入库,也就是当前发送的消息记录保存到数据库,然后再用最终一致性来保证两边的事务完整性。

MQ最终一致性流程

  1. 一键注册登录,初次生成创建用户账号,用户表新增记录。
  2. 保存本地消息记录,说明当前MQ用于初始化简历
  3. 发送消息给MQ
  4. 监听消息,
  5. 消费消息,初始化简历,新增简历记录
  6. 根据简历初始化结果进行ack的确认或失败 6.1. 简历初始化成功,手动ack确认,并且删除对应的本地消息表记录
  7. 6.2. 简历初始化失败,ack失败,重回队列

最终一致性落地(1) - 异步解耦微服务

API中创建InitResumeMQConfig

消息队列配置类: 建议直接拷贝以前的进行修改:

@Configuration
public class InitResumeMQConfig {// 定义交换机的名称public static final String INIT_RESUME_EXCHANGE = "init_resume_exchange";// 定义队列的名称public static final String INIT_RESUME_QUEUE = "init_resume_queue";// 统一定义路由keypublic static final String ROUTING_KEY_INIT_RESUME = "init.resume.display";// 创建交换机@Bean(INIT_RESUME_EXCHANGE)public Exchange exchange() {return ExchangeBuilder.topicExchange(INIT_RESUME_EXCHANGE).durable(true).build();}// 创建队列@Bean(INIT_RESUME_QUEUE)public Queue queue() {return QueueBuilder.durable(INIT_RESUME_QUEUE).build();}// 创建绑定关系@Beanpublic Binding initResumeBinding(@Qualifier(INIT_RESUME_EXCHANGE) Exchange exchange,@Qualifier(INIT_RESUME_QUEUE) Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("init.resume.#").noargs();}}

授权服务

UsersService中新增业务方法,用于测试MQ一致性:

UsersService实现:

此时的创建用户就是不同的插入操作了:

工作服务

创建监听消费类:

yml添加配置:

测试

为了测试方便,使用固定1234验证码则直接通过:

通过消息队列的监听来实现两边数据表的插入记录。

 最终一致性落地(2) - 存储本地消息

创建消息数据表

逆向工具生成消息表的entity、mapper等并复制到项目中(步骤略)。

保存本地消息

创建生产者助手类:

保存消息到本地:

调用端代码,此时MQ消息不发送,先保存到数据库,然后再提交以后进行消息发送:

测试运行

检查消息表有没保存到新纪录

最终一致性落地(3) - 自定义事务管理器发送MQ消息

创建我的自定义事务管理器

重写事务提交方法,提交后,不管怎样,执行并且发消息给消费端,让第二个微服务进行事务处理

增加批量查询的方法

断点测试

打断点,测试流程是怎么走的。 观察消息的id以及消息内容是否ok。

最终一致性落地(4) - 确认并删除本地消息

消息一旦消费成功,则需要进行处理,把消息记录从本地数据库中删除。

开启MQ的手动ACK机制

成功则删除消息,并且ack确认,失败则重回队列:

可以看到,失败的消息,由于没有ack,他会一直存在于队列中,直到成功,那么会删除数据表中对应的消息,如此,本地消息数据表最终会清空。

模拟异常

测试

观察日志:

apipost可以并发测试:

最终测试结束,消息表全部清空,最终一致性的目的达到

相关文章:

【SpringCloud】 微服务分布式环境下的事务问题,seata大合集

目录 微服务分布式环境下的事务问题 分布式事务 本地事务 BASE理论与强弱一致性 BASE理论 强弱一致性 常见分布式事务解决方案 - 2PC 常见分布式事务解决方案 - TCC 常见分布式事务解决方案 - 最大努力通知 常见分布式事务解决方案 - 最终一致性 Seata介绍与术语 Seata…...

vite5+vue3开发阅读APP实战笔记20240725

目前界面长成这样&#xff1a; 配置别名 修改vite.config.js import {defineConfig} from vite import vue from vitejs/plugin-vue import path from "path"// https://vitejs.dev/config/ export default defineConfig({server: {open: true,port: 8088,},plug…...

Intel任命Micron技术开发主管领导Intel Foundry制造运营

- **新闻要点**&#xff1a;Intel聘请了Micron的技术开发主管Dr. Naga Chandrasekaran担任首席全球运营官、执行副总裁以及Intel Foundry制造和供应链组织的总经理。他将负责Intel的所有制造运营事务。 #### 任命背景 - **领导团队**&#xff1a;Chandrasekaran将成为Intel执行…...

苹果发布iOS 18 Beta 4,新增CarPlay 壁纸等多项功能改进

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 iOS 18 Beta 4&#xff1a;新功能与改进的探索 苹果公司在2024年7月9日向开发者推送了iOS 18的第四个开发者预览版Beta 4更新&#xff0c;内部…...

谷粒商城实战笔记-50-51-商品分类的删除

文章目录 一&#xff0c;50-商品服务-API-三级分类-删除-逻辑删除1&#xff0c;逻辑删除的配置1.1 配置全局的逻辑删除规则&#xff08;可省略&#xff09;1.2 配置逻辑删除Bean&#xff08;可省略&#xff09;1.3 Bean相应字段上加上注解TableLogic 2&#xff0c;后台接口开发…...

vue3+g2plot实现词云图

词云图 效果预览: 核心代码: import {WordCloud } from @antv/g2plot;fetch(https://gw.alipayobjects.com/os/antfincdn/jPKbal7r9r/mock.json).then((res) => res.json()).then((data) => {const wordCloud = new WordCloud(container, {data,wordField: x,weigh…...

Golang | Leetcode Golang题解之第273题整数转换英文表示

题目&#xff1a; 题解&#xff1a; var (singles []string{"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"}teens []string{&…...

使用C#手搓Word插件

WordTools主要功能介绍 编码语言&#xff1a;C#【VSTO】 1、选择 1.1、表格 作用&#xff1a;全选文档中的表格&#xff1b; 1.2、表头 作用&#xff1a;全选文档所有表格的表头【第一行】&#xff1b; 1.3、表正文 全选文档中所有表格的除表头部分【除第一行部分】 1.…...

WordPress主题追格企业官网主题免费开源版V1.1.6

追格企业官网主题免费开源版由追格开发的一款开源wordpress主题&#xff0c;专为企业建站和追格企业官网小程序&#xff08;开源版&#xff09;PC配套而设计&#xff0c;功能集新闻动态、留言反馈、产品与服务、公司简介、联系我们等模块。...

uniapp引入自定义图标

目录 一、选择图标&#xff0c;加入购物车 二、下载到本地 三、导入项目 四、修改字体引用路径 五、开始使用 这里以扩展iconfont图标为例 官网&#xff1a;iconfont-阿里巴巴矢量图标库 一、选择图标&#xff0c;加入购物车 二、下载到本地 直接点击下载素材&#xff0…...

pytorch-scheduler(调度器)

scheduler简介 scheduler(调度器)是一种用于调整优化算法中学习率的机制。学习率是控制模型参数更新幅度的关键超参数,而调度器根据预定的策略在训练过程中动态地调整学习率。 优化器负责根据损失函数的梯度更新模型的参数,而调度器则负责调整优化过程中使用的特定参数,通…...

防火墙与入侵检测系统(IDS/IPS)在现代网络安全中的关键角色

在数字化日益加速的今天&#xff0c;网络安全变得尤为重要。随着网络攻击的复杂性和频率不断增加&#xff0c;保护关键信息资产已成为各大小组织的首要任务。防火墙&#xff08;Firewall&#xff09;和入侵检测系统&#xff08;Intrusion Detection System&#xff0c;IDS&…...

Python 之 os、open、json、pickle 模块的“疯狂”探险记

1.open函数的使用 Python 中的 open() 函数是处理文件的标准方法。它允许你打开一个文件&#xff0c;并对其进行读取、写入或追加操作 open(file,mode,encoding)函数的格式&#xff1a;file&#xff1a;文件路径 mode&#xff1a;打开方式&#xff08;读&#xff1a; r写&…...

CTF-Web习题:2019强网杯 UPLOAD

题目链接&#xff1a;2019强网杯 UPLOAD 解题思路 打开靶场如下图所示&#xff0c;是一个注册和登录界面 那就注册登录一下&#xff0c;发现是一个提交头像的页面&#xff1a; 试了一下只有能正确显示的png图片才能提交成功&#xff0c;同时F12拿到cookie&#xff0c;base6…...

Unity环境渲染与反射探针的深入探索

目录 环境渲染基础 光源设置 材质与光照贴图 反射探针&#xff08;Reflection Probes&#xff09;详解 反射探针的创建与配置 材质中的反射探针设置 实践案例 实践案例&#xff1a;室内场景中的反射效果 场景设置 反射探针配置 Unity代码示例&#xff08;非直接配置…...

vue3 父组件 props 异步传值,子组件接收不到或接收错误

1. 使用场景 我们在子组件中通常需要调用父组件的数据&#xff0c;此时需要使用 vue3 的 props 进行父子组件通信传值。 2. 问题描述 那么此时问题来了&#xff0c;在使用 props 进行父子组件通信时&#xff0c;因为数据传递是异步的&#xff0c;导致子组件无法成功获取数据…...

[C++]TinyWebServer

TinyWebServer 文章目录 TinyWebServer1 主体框架2 Buffer2.1 向Buffer写入数据2.2 从Buffer读取数据2.3 动态扩容2.4 从socket中读取数据2.5 具体实现 3 日志系统3.1 生产者-消费者模型3.2 数据一致3.3 代码 4 定时器4.1 调整堆中元素操作4.2 堆的操作4.2.1 增4.2.2 删4.2.3 改…...

Uniswap价格批量查询与ws订阅行情

Uniswap价格批量查询与ws订阅行情 由于 Uniswap V1 版本必须包含 ETH 所以两个 token 之间交换必须先换成 ETH 去中转效率很低已经弃用了 由于 V3 版本 CLMM 和 V4 版本的 DLMM 数学模型过于复杂&#xff0c;还是先从 AMM 模型的 V2 进行入门和学习 Uniswap 三种合约 Unisw…...

vue 实战 区域内小组件元素拖拽 示例

<template><div><el-button type"primary" click"showDialog true">快捷布局</el-button><el-dialog title"快捷布局配置" :visible.sync"showDialog"><el-row :gutter"20"><el-co…...

C++多线程编程中的锁详解

在现代软件开发中&#xff0c;多线程编程是提升应用程序性能和响应能力的重要手段。然而&#xff0c;多线程编程也带来了数据竞争和死锁等复杂问题。为了确保线程间的同步和共享数据的一致性&#xff0c;C标准库提供了多种锁机制。 1. std::mutex std::mutex是最基础的互斥锁…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...