事务及分布式事务解决方案

news2024/11/20 8:40:42

基础概念

1.1.事务

事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。

1.2.本地事务

在计算机系统中,更多的是通过关系型数据库来控制事务,利用数据库本身的事务特性来实现,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。

数据库事务的四大特性 ACID:

  • A(Atomic)原子性

构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。 

  • C(Consistency)一致性

在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转100元, 转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出100元,李四账户没有增加100元这就出现了数据错误,就没有达到一致性。

  • I(Isolation)隔离性

数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题。

  • D(Durability)持久性

事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。 数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。

1.3事务的属性

        1.传播行为(事务的传递):

        2.隔离级别(控制并发的弊端):

        3.只读(优化);

        4.超时(释放资源);

        5.回滚规则(指定要不要再出错后回滚事务);

1.4使用Spring注解管理传播行为

// 如果有事务,那么加入事务,没有的话新建一个(默认)
1)@Transactional(propagation=Propagation.REQUIRED)
// 容器不为这个方法开启事务(如果有事务将其挂起,执行方法)
2)@Transactional(propagation=Propagation.NOT_SUPPORTED)
// 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
3)@Transactional(propagation=Propagation.REQUIRES_NEW)
// 必须在一个已有的事务中执行,否则抛出异常
4)@Transactional(propagation=Propagation.MANDATORY)
// 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
5)@Transactional(propagation=Propagation.NEVER)
// 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
6)@Transactional(propagation=Propagation.SUPPORTS)
//内嵌到一个事务里面,当运行到内部Transaction时会停止,执行内部的Transaction 等其执行完了才执行外部的;

7)@Transactional(propagation=Propagation.NESTED)
/*
public void methodName(){
    // 本类的修改方法 1
    update();
    // 调用其他类的修改方法
    otherBean.update();
    // 本类的修改方法 2
    update();
}
other失败了不会影响 本类的修改提交成功
本类update的失败,other也失败
*/

1.5事务中经常出现的并发问题

脏读:一个事务读取了另一个事务操作但未提交的数据。

不可重复读:一个事务中的多个相同的查询返回了不同数据。

幻读:事务并发执行时,其中一个事务对另一个事务中操作的结果集的影响。

1.6SQL规范定义的四个事务隔离级别

以上事务中经常发生的问题,为了兼顾并发效率和异常控制,SQL规范定义了四个事务隔离级别:

  • Read uncommitted (读未提交)

如果设置了该隔离级别,则当前事务可以读取到其他事务已经修改但还没有提交的数据。这种隔离级别是最低的,会导致上面所说的脏读

  • Read committed (读已提交)

如果设置了该隔离级别,当前事务只可以读取到其他事务已经提交后的数据,这种隔离级别可以防止脏读,但是会导致不可重复读和幻读。这种隔离级别最效率较高,并且不可重复读和幻读在一般情况下是可以接受的,所以这种隔离级别最为常用。

  • Repeatable read (可重复读、默认)

如果设置了该隔离级别,可以保证当前事务中多次读取特定记录的结果相同。可以防止脏读、不可重复读,但是会导致幻读。

  • Serializable(串行化)

如果设置了该隔离级别,所有的事务会放在一个队列中执行,当前事务开启后,其他事务将不能执行,即同一个时间点只能有一个事务操作数据库对象。这种隔离级别对于保证数据完整性的能力是最高的,但因为同一时刻只允许一个事务操作数据库,所以大大降低了系统的并发能力。

按隔离级别由弱到强:

3655ea4ff8c30ca09efd674e0b1afd7f.png

1.7查看事务隔离级别

命令行登录mysql,查看当前事务隔离级别:

select @@tx_isolation; 或者  select @@session.tx_isolation;

1.8Spring事务配置

  • 只读

// readOnly=true只读,不能更新,删除
@Transactional (propagation = Propagation.REQUIRED,readOnly=true)
  • 超时;释放资源

// 设置超时时间
@Transactional (propagation = Propagation.REQUIRED,timeout=30)
  • 回滚规则

默认throw new RuntimeException("...");会回滚

需要捕获的throw new Exception("...");不会回滚

// 指定回滚
@Transactional(rollbackFor=Exception.class)
public void methodName() {
    // 会回滚
    throw new Exception("...");
    // 会回滚
    throw new RuntimeException("...");
}
//指定不回滚
@Transactional(noRollbackFor=Exception.class)
public ItimDaoImpl getItemDaoImpl() {
    // 会回滚
    throw new RuntimeException("注释");
}
//rollbackFor 默认是 RuntimeException
@Transactional(rollbackFor=class)//@Transactional()
public ItimDaoImpl getItemDaoImpl() {
     // 不会回滚
     throw new Exception("...");
     // 会回滚  
     throw new RuntimeException("");   
}    

本地事务

Begin transaction
    update A set amount = amount-100 where user_id = 1;
    update B set amount = amount+100 where user_id = 1;
end transaction
commit;

使用spring一个注解搞定上述事务功能

@Transactional(rollbackFor=Exception.class)
public voud update() {
     updateA();
     updateB();
}  

1.9分布式事务

随着互联网的快速发展,软件系统由原来的单体应用转变为分布式微服务应用。事务由于网络问题远程调用等导致数据不一致,即分布式事务问题。


2.0分布式事务产生的场景

  • 跨JVM进程产生分布式事务

典型的场景就是微服务架构 微服务之间通过远程调用完成事务操作。

  • 跨数据库实例产生分布式事务

单体系统访问多个数据库实例 当单体系统需要访问多个数据库(实例)时就会产生分布式事务。 比如:用户信 息和订单信息分别在两个MySQL实例存储,用户管理系统删除用户信息,需要分别删除用户信息及用户的订单信 息,由于数据分布在不同的数据实例,需要通过不同的数据库链接去操作数据,此时产生分布式事务。

  • 多服务访问同一个数据库实例

跨JVM进程,两个微服务持有了不同的数据库连接进行数据库操作,此时产生分布式事务。

2.1CAP理论

CAP是 Consistency、Availability、Partition tolerance三个词语的缩写,分别表示一致性、可用性、分区容错性。

  • C - Consistency一致性

一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意结点读取到的数据都是最新的状态。

  • A - Availability可用性

可用性是指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。

  • P - Partition tolerance分区容错性

分布式系统的各结点部署在不同的子网,不可避免的会出现由于网络问题而导致结点之间通信失败,此时仍可对外提供服务。

CAP 不可能都取,只能取其中2个的原因如下:

  • 如果C是第一需求的话,那么会影响A的性能,因为要数据同步,不然请求结果会有差异,但是数据同步会消耗时间,期间可用性就会降低。
  • 如果A是第一需求,那么只要有一个服务在,就能正常接受请求,但是对于返回结果变不能保证,原因是,在分布式部署的时候,数据一致的过程不可能想切线路那么快。
  • 再如果,同时满足一致性和可用性,那么分区容错就很难保证了,也就是单点,也是分布式的基本核心。

2.2Base理论

BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩 写。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证 核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,称之为“柔 性事务”。

  • 基本可用Basically Available

分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。如,电商网站交易付款出 现问题了,商品依然可以正常浏览。

  • 软状态Soft state

由于不要求强一致性,所以BASE允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用 性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。

  • 最终一致Eventually consistent

最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变 为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。

2.3分布式事务解决方案

2PC(两阶段提交)

2PC即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2是指两个阶段,P是指准备阶段,C是指提交阶段。

  1. 准备阶段(Prepare phase):事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事 务,并写本地的Undo/Redo日志,此时事务没有提交。(Undo日志是记录修改前的数据,用于数据库回滚,Redo日志是记录修改后的数据,用于提交事务后写入数据文件)
  2. 提交阶段(commit phase):如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者 发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源。

2PC两段提交的缺点

二阶段提交看似能够提供原子性的操作,但它存在着的缺陷

  • 网络抖动导致的数据不一致: 第二阶段中协调者参与者发送commit命令之后,一旦此时发生网络抖动,导致一部分参与者接收到了commit请求并执行,可其他未接到commit请求的参与者无法执行事务提交。进而导致整个分布式系统出现了数据不一致。

  • 超时导致的同步阻塞问题: 2PC中的所有的参与者节点都为事务阻塞型,当某一个参与者节点出现通信超时,其余参与者都会被动阻塞占用资源不能释放。

  • 单点故障的风险: 由于严重的依赖协调者,一旦协调者发生故障,而此时参与者还都处于锁定资源的状态,无法完成事务commit操作。虽然协调者出现故障后,会重新选举一个协调者,可无法解决因前一个协调者宕机导致的参与者处于阻塞状态的问题。

3PC(三阶段提交)

三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC2PC的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当参与者各种原因未收到协调者的commit请求后,会对本地事务进行commit,不会一直阻塞等待,解决了2PC的单点故障问题,但3PC 还是没能从根本上解决数据一致性的问题。

3PC 的三个阶段分别是CanCommitPreCommitDoCommit

  • CanCommit:协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。
  • PreCommit协调者向所有参与者发送PreCommit命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。
  • DoCommit:在前两个阶段中所有参与者的响应反馈均是YES后,协调者向参与者发送DoCommit命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送abort请求命令,执行事务的中断。

XA方案

基于2PC实现的规范,是强一致性分布式事务。由数据实现的2PC规范,关系型数据库有MySQl、Oracle等。

XA 规范

xa_start: 负责开启或者恢复一个事务分支,并且管理 XID 到调用线程。

xa_end: 负责取消当前线程与事务分支的关联。

xa_prepare: 询问 RM 是否准备好提交事务分支。

—————— 第一阶段提交 —————————

如果是单机,可以直接跳过 prepare 和第二阶段,输入 one phase commit 事务id 直接进行提交即可。

xa_commit: 通知 RM 提交事务分支。

xa_rollback: 通知 RM 回滚事务分支。

xa_recover: 需要恢复的 XA 事务。

—————— 第二阶段提交 —————————

XA 二阶段提交

一阶段:执行 XA PREPARE 语句。
二阶段:执行 XA COMMIT/ROLLBACK 语句。

XA 协议存在的问题

  1. 同步阻塞问题:一般情况下,不需要调高隔离级别,XA 默认不会改变隔离级别。

  2. 单点故障成熟的 XA 框架需要考虑 TM 的高可用性

  3. 数据不一致极端情况下,一定有事务失败问题,需要监控和人工处理

解决 XA 数据不一致方案:

  • 日志存储:记录 XA 事务在每个流程中的执行状态。
  • 自定义事务恢复:通过 XA recovery 命令从资源管理器中获取需要被恢复的事务记录,然后根据 XID 匹配应用程序中存储的日志,根据事务状态进行提交或回滚。

本地消息表

将分布式事务拆分成本地事务进行处理,保证最终一致性。

处理流程:

  1. 事务发起方把要处理的业务事务和写消息表这两个操作放在同一个本地事务里。
  2. 事务发起方有一个定时任务轮询消息表,把没有处理的消息发送到消息中间件。
  3. 事务被动方从消息中间件获取到消息后,返回成功。
  4. 事务发起方更新消息状态为已成功。

注意:消息的接收方即事务被动方需要做幂等。

create table tx_message
(
    id           bigint auto_increment primary key,
    orderly      tinyint      not null comment '是否为顺序消息',
    topic        varchar(64)  not null comment 'MQ topic',
    sharding_key varchar(128) not null comment 'ShardingKey,用于选择不同的 partition',
    tag          varchar(128) not null comment 'Message Tag 信息',
    msg_id       varchar(64)  not null comment 'Msg ID 只有发送成功后才有数据',
    msg_key      varchar(64)  not null comment 'MSG Key,用于查询数据',
    msg          longtext     not null comment '要发送的消息',
    retry_time   tinyint      not null comment '重试次数',
    status       tinyint      not null comment '发送状态:0-初始化,1-发送成功,2-发送失败',
    create_time  datetime     not null,
    update_time  datetime     not null,
    index idx_update_time_status(update_time, status)
);

事务消息

将本地消息表存储和扫描事务消息的事,由消息中间件RocketMQ完成。支持事务消息的消息中间件只有RocketMQ。

实现流程

  1. 发起方发送半事务消息给RocketMQ,此时消息的状态为prepare,接收方还不能拉渠道此消息。
  2. 发起方进行本地事务操作。
  3. 发起方给RocketMQ确认提交消息,接受消费此消息。

TCC补偿事务

TCC(Try-Confirm-Cancel)又被称补偿事务,是应用层面的2PC,需要编写业务逻辑来实现。

Try阶段:

业务操作时通过Try操作去操作数据库预留资源。

Confirm阶段:

确认执行业务操作,在只预留的资源基础上,发起操作请求。

Cancel阶段:

只要涉及到的相关业务中,有一个业务方预留资源未成功,则取消所有业务资源的预留请求。

TCC的缺点:

  • 应用侵入性强:TCC由于基于在业务层面,致使每个操作都需要有 tryconfirmcancel三个接口。

  • 开发难度大:代码开发量很大,要保证数据一致性 confirm 和 cancel 接口还必须实现幂等性。

Saga

Saga是一个长活事务可被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务。

  • 每个Saga由一系列sub-transaction Ti 组成

  • 每个Ti 都有对应的补偿动作Ci,补偿动作用于撤销Ti造成的结果

Saga没有Try,直接commit。Saga不提供ACID保证,因为原子性和隔离性不能得到满足。通过saga log,saga可以保证一致性和持久性。Saga保证所有的子事务都得以完成或补偿,但Saga系统本身也可能会崩溃。

Saga的实现

  1. Saga状态机实现。
  2. Saga AOP Proxy实现。

Saga模式适用于业务流程长、业务流程多的业务;在银行金融机构使用广泛。

seata

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/495597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP 从入门到放弃系列之批次追溯功能

首先执行MB57,建立批次追溯关系,并存储在CHVW表。根据情况选择要追溯的期间,在过账日期范围内填写。 不勾选‘基于清单显示’,为ALV显示结果 勾选‘基于清单显示’,为清单显示结果 执行MB56,查询批次追溯 可以设置显示…

【.NET AI Books 前言】Azure OpenAI Service 入门

本书是为 .NET 开发者而写的,让 .NET 开发者能快速掌握 Azure OpenAI Service 的使用技巧。 ChatGPT 的到来意味着我们已经置身于 AI 引起的全新变革中,作为开发者你可能将面临几种改变: GPT 模型到来后,如何去架构好企业解决方案…

Dex-Net 2.0<论文>

题目:Deep Learning to Plan Robust Grasps with Synthetic Point Clouds and Analytic Grasp 引言 传统抓取方法的局限性 缺乏泛化能力需要大量计算资源和手工标注数据【前两种依赖物体形状、材料、质量等先验知识通常要对物体建模姿态评估运动学分析】只能处理…

【C语言】深入理解注释

文章目录 一. 预处理阶段对注释的处理二. 注释使用时的注意事项1. C风格的注释无法嵌套使用2. 基本注释注意事项3. 注释导致的二义性 四. 关于注释的一个使用建议 一. 预处理阶段对注释的处理 我们知道一个源文件要变成可执行程序的话,首先要经过预处理&#xff0c…

Vtk7.1.1+PCL1.12.0安装

错误可参考:Ubuntu20.04 编译 pcl1.8可能出现的问题 安装参考1:ubuntu20.04下安装pcl_ubuntu安装pcl_Yuannau_jk的博客-CSDN博客 安装参考2:Ubuntu20.04 安装pcl详细教程_ubuntu20.04安装pcl_LYiiiiiii的博客-CSDN博客 安装参考3&#xff1a…

涨知识!你不知道的中国手机号码的编码和划分规则

引言 在当今信息化的时代,移动电话号码已经成为人们日常生活中必不可少的联系方式。中国作为世界上拥有庞大人口数量的国家之一,移动电话号码的编码和划分显得尤为重要。 中国的移动电话号码分为三大运营商,每个运营商又有自己的号码段&…

Spring Security OAuth2.0(三)-----基于Redis存储和JDBC存储

问题 令牌往哪里存? 客户端信息入库 第三方应用优化 1.令牌往哪里存? 在我们配置授权码模式的时候,有两个东西当时存在了内存中: InMemoryAuthorizationCodeServices 这个表授权码存在内存中。InMemoryTokenStore 表示生成的令…

open3D

一、说明 对于点云 处理,这里介绍哦pen3d,该软件和opencv同样是interl公司的产品。 Open3D 是一个开源库,支持快速开发处理 3D 数据的软件。 Open3D 前端在 C 和 Python 中公开了一组精心挑选的数据结构和算法。后端经过高度优化,…

Spring Boot处理CORS跨域请求的三种方法

1 前言 Springboot跨域问题,是当前主流web开发人员都绕不开的难题。但我们首先要明确以下几点 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境跨域请求能发出去,服务端能收到请求并正常返回结果,只是结…

05-权限分配 尚筹网

权限控制 权限控制机制的本质就是“用钥匙开锁”。 在实现权限控制之前,这里先完成给Admin分配Role和给Role分配Auth的功能。 一、给Admin分配Role 目标 ​ 通过前端页面操作,将Admin与Role之间的关系保存到数据库 思路 ​ 给下面的按钮&#xff…

【ED合集】事件检测的文章

1 CorED: Incorporating Type-level and Instance-level Correlationsfor Fine-grained Event Detection 论文来源:SIGIR 2022(CCF A类会议) 论文链接:https://dl.acm.org/doi/pdf/10.1145/3477495.3531956 代码链接:GitHub - JiaweiSheng…

抖音小程序|基于天气API实现天气预报功能

文章目录 一、前言包含了功能UI展示 二、开发前的准备三、开发步骤1.app.js 配置2.pages/index.js 演示二维码源码在百度网盘下载 一、前言 参考老版iPhone自带的天气预报APP。目前只有一个界面UI, 后续会更新出更多功能; 包含了功能 - 实况预报 - 未来48小时 - 未来一周的天…

动态gif图片如何在线做?轻松实现图片在线生成gif

常见的jpg、png格式的静态图片想要变成gif格式的动态图片时,要怎么办呢?有没有什么简单实用的gif制作工具呢? 一、什么工具能够在线制作gif? GIF中文网作为一款专业的gif制作(https://www.gif.cn/)工具&a…

Golang - slice 内部实现原理解析

Golang - slice 内部实现原理解析 一.Go中的数组和slice的关系 1.数组 在几乎所有的计算机语言中,数组的实现都是一段连续的内存空间,Go语言数组的实现也是如此,但是Go语言中的数组和C语言中数组还是有所不同的 C语言数组变量是指向数组第…

鸿蒙Hi3861学习七-Huawei LiteOS(信号量)

一、简介 信号量(Semaphore)是一种实现任务间通信的机制,实现任务之间同步或临界资源的互斥访问。常用于协助一组相互竞争的任务来访问临界资源。 在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功…

阿里工作7年,肝到P8就靠这份学习笔记了,已助14个朋友拿到offer

​ 在阿里工作了7年,工作压力大,节奏快,但是从技术上确实得到了成长,尤其是当你维护与大促相关的系统的时候,熬到P8也费了不少心思。 技术的更新迭代越来越快,程序员或许是这个过程中最为挣扎的一波人。每…

第0章 学习之前的准备

突然想写点关于linux的东西,一是将自己几十年来零碎的知识作以串联,二是能为正在学习路上的新手作些指引。而恰好作者的孩子是一位初一的学生,我写的这些东西也正是我手把手教授他的,现在分享出来并且命名为《linux中学教程》&…

记一次SpringBoot应用性能调优过程

背景 使用SpringBoot、MyBatis-Plus开发一个接口转发的能,将第三方接口注册到平台中,由平台对外提供统一的地址,平台转发时记录接口的转发日志信息。开发完成后使用Jmeter进行性能测试,使用100个线程、持续压测180秒,…

Java中池化技术探讨

背景:在日常开发中,除了考虑IO操作、线程上下文切换、GC的影响性能外。还通过池化技术提高性能通过循环复用资源,降低资源创建和销毁带来的开销和损失,从而提高性能,例如对象池、内存池、线程池、连接池 一、对象池&a…

软件测试 - 测试用例设计方法之等价类划分和边界值分析

1. 等价类划分法 1.1 基本理论 等价类划分法是通过科学的方法找到具有共同特性的测试输入的集合,避免进行穷举测试,大大减少了测试用例的数量,从而提高测试效率。等价类划分法的典型应用场景就是输入框,适用于较少数量输入框的场…