数据库原理之数据库事物

news2024/11/24 6:51:16

文章目录

  • 一、事物介绍
    • 1.1 事物的目的是保证数据的一致性
    • 1.2 事物的ACID A、I、D是为了实现 C
    • 1.3 什么是本地事物(Local Transactions)
  • 二、数据库系统如何实现ACID
    • 2.1 影响深远的ARIES理论
    • 2.2 本地事物如何实现原子性和持久性 A、D
      • 2.2.1 实现原子性和持久性的Commit Logging方法
      • 2.2.2 基于ARIES Commit Logging 的升级 Write-Ahead Logging
      • 2.2.3 SQLite的 Shadow Paging (影子分页)方案实现的事物机制
    • 2.3 本地事物如何实现隔离性(Isolation)
      • 2.3.1 隔离性有什么用?
      • 2.3.2 现代数据库都提供了三种锁
      • 2.3.3 本地事物的四种隔离级别的实现
      • 2.3.4 MVCC 无锁的隔离场景优化方案
      • 2.3.5 乐观加锁和悲观加锁

内容总结

  1. 事物的目的是保证数据的一致性;事物的ACID中A、I、D都是为了实现C 一致性!
  2. 各家数据库事物都参考了ARIES理论;
  3. 原子性和持久性的实现方案:Commit Logging、Write-Ahead Logging、Shadow Paging;
  4. 隔离性保证了每个事物各自读、写的数据相互独立,不会彼此影响;
  5. 数据库通用的三种锁,写锁、读锁、范围锁;
  6. 不同隔离级别以及幻读、脏读等问题都只是表面现象,它们是各种锁在不同加锁时间上组合应用所产生的结果,锁才是根本的原因。
  7. MVCC优化事物“读+写”的事物隔离场景;




一、事物介绍

1.1 事物的目的是保证数据的一致性

事务处理几乎是每一个信息系统中都会涉及到的问题,它存在的意义就是保证系统中的数据是正确的,不同数据间不会产生矛盾,也就是保证数据状态的一致(Consistency)。

1.2 事物的ACID A、I、D是为了实现 C

  • 原子性(Atomic):在同一项业务处理过程中,事务保证了多个对数据的修改,要么同时成功,要么一起被撤销。
  • 隔离性(Isolation):在不同的业务处理过程中,事务保证了各自业务正在读、写的数据互相独立,不会彼此影响。
  • 持久性(Durability):事务应当保证所有被成功提交的数据修改都能够正确地被持久化,不丢失数据。
  • 一致性(Consistency):是数据库处理前后结果应与其所抽象的客观世界中真实状况保持一致。这种一致性是一种需要管理员去定义的规则。管理员如何指定规则,数据库就严格按照这种规则去处理数据。

1.3 什么是本地事物(Local Transactions)

  1. 本地事物也称为局部事物
  2. 本地事务是最基础的一种事务处理方案,通常只适用于单个服务使用单个数据源的场景,它是直接依赖于数据源(通常是数据库系统) 本身的事务能力来工作的。
  3. 本地事务的开启、终止、提交、回滚、嵌套、设置隔离级别、乃至与应用代码贴近的传播方式,全部都要依赖底层数据库的支持分布式事物中的 XA、TCC、SAGA 等主要靠应用程序代码来实现的事务,有着十分明显的区别。



二、数据库系统如何实现ACID

2.1 影响深远的ARIES理论

现代的主流关系型数据库(Oracle、Microsoft SQLServer、MySQL-InnoDB、IBM DB2、PostgreSQL,等等)在事务实现上都深受该理论的影响

ARIES的全称 Algorithms for REcovery and Isolatiion Expliting Sematics 基于语义的恢复与隔离算法。

2.2 本地事物如何实现原子性和持久性 A、D

原子性和持久性在事务里是密切相关的两个属性,原子性保证了事务的多个操作要么都生效要么都不生效,不会存在中间状态;持久性保证了一旦事务生效,就不会再因为任何原因而导致其修改的内容被撤销或丢失。

原子性和持久性的难度在于,写入持久化介质的动作不是原子的,除了已写入未写入,还有正在写入的状态。
数据写入数据库可能会发生崩溃,需要进行崩溃恢复的场景。

  1. 未提交事务时,数据库崩溃需要回滚不完整的事物
  2. 已提交事物数据未写入数据库, 数据库需要将数据重新写入。

2.2.1 实现原子性和持久性的Commit Logging方法

  1. 为了能完成崩溃恢复,数据库会将修改数据操作所需的全部信息,以日志追加的形式写入到磁盘日志文件中 一般称为 Redo Log。
  2. 事物提交日志新增一条CommitRecord后,数据库会根据日至上的信息进行数据修改。修改完成后在日志中加入一条End Logging记录。标识事物已经完成持久化。
  3. Commit Logging实现的持久性:日志一旦被写入 Commit Record 那么整个事物就是成功的,即使修改数据时崩溃,也可以根据日志恢复现场继续写入。
  4. Commit Logging实现的原子性:如果有Commit Record没有End Record那么就可根据日志回滚数据
  5. 阿里的OceanBase就是使用Commit Logging实现事物

缺陷 所有真实的修改,都发生在事物提交、日志写入Commit Record之后,这样的话磁盘IO就会集中在事物提交后,无法利用I/O空闲的时间。

2.2.2 基于ARIES Commit Logging 的升级 Write-Ahead Logging

Write-Ahead Logging的改进方案就是允许在事物提交之前提前写入变动数据。

Write-Ahead Logging将数据写入的时机,按照事物提前后分成了FORCE和STEAL

  • FORCE 事物提交后,要求数据立即写入称为FORCE(即使日志文件没有写入也会提交)。 不强制数据同步写入称为NO-FORCE。大部分数据库都是采用了No-FORCE策略。因为有了日志可以随时持久化,没有必要立即进行数据写入。
  • STEAL 在事物提交前,允许变动数据提前写入,则称为STEAL 不允许则称为 NO-STEAL 。 从优化I/O性能考虑,允许数据提前写入有利于利用空闲的I/O资源,也可以节省数据库缓冲区占用的内存。

Commit Logging机制允许NO-FORCE但是不允许STEAL

  • 如果允许STEAL,当一个事务正在执行时,另一个事务可以直接读取该事务已经提交的数据,就会出现这种竞态条件。
  • Commit Logging事务的实现一般都不允许STEAL,而是采用其他的方式来解决竞态条件,例如使用MVCC(多版本并发控制)机制来控制数据的访问。在MVCC机制中,每个事务都会有一个自己的数据视图,其他事务无法访问该事务未提交的数据,从而避免了竞态条件的发生。

Write-Ahead Logging 允许NO-FORCE 也允许STEAL(Undo Log实现)

  • Write-Ahead Logging增加了一种 Undo Log日志。变动数据写入磁盘前,先记录Undo Log、记录了数据被修改的过程,包括新的值和原始值。事物崩溃或者回滚时,可以根据Undo log对提前写入的数据进行擦除。

Write-Ahead Logging 的崩溃恢复

  • 分析 Analysis:从最后一次检查点CheckPoint(正常状态) 找出未结束的事物也就是没有end Record的日志。组成待恢复的集合
  • 重做 Redo : 从第一步找出的历史事物中,如果事物已经包含Commit Record 将这些记录写入磁盘,然后增加End Record 这条事物,就从待恢复事物集合中移除。
  • 回滚 Undo:该阶段将重做后剩余的需要回滚的事物,被称为Loser 根据Undo Log 中的信息回滚这些事物。
  • 重做、回滚都需要设计为幂等的,这三个阶段的复杂度都非常高。

FORCE和STEAL的组合

数据库按照“是否允许 FORCE 和 STEAL”可以产生四种组合,从优化磁盘 I/O 的角度看,NO-FORCE 加 STEAL 组合的性能无疑是最高的;从算法实现与日志的角度看,NO-FORCE 加 STEAL 组合的复杂度无疑是最高的。

image.png


2.2.3 SQLite的 Shadow Paging (影子分页)方案实现的事物机制

Shadow Paging 的大体思路是对数据的变动会写到硬盘的数据中,但并不是直接就地修改原先的数据,而是先将数据复制一份副本,保留原数据,修改副本数据。在事务过程中,被修改的数据会同时存在两份,一份修改前的数据,一份是修改后的数据,这也是“影子”(Shadow)这个名字的由来。
当事务成功提交,所有数据的修改都成功持久化之后,最后一步要修改数据的引用指针,将引用从原数据改为新复制出来修改后的副本,最后的“修改指针”这个操作将被认为是原子操作,所以 Shadow Paging 也可以保证原子性和持久性。
缺陷: Shadow Paging 相对简单,但涉及到隔离性与锁时,Shadow Paging 实现的事务并发能力相对有限,因此在高性能的数据库中应用不多



2.3 本地事物如何实现隔离性(Isolation)

2.3.1 隔离性有什么用?

隔离性保证了每个事物各自读、写的数据相互独立,不会彼此影响。隔离性和并发密切相关,如果一切都是串行的那么这样的访问具有天然的隔离性。

2.3.2 现代数据库都提供了三种锁

这些是按照锁的功能划分的分类,如果按照粒度分类还有表锁、行锁、页锁等等

  • 写锁 Write Lock:
    • 也叫排它锁 eXclusive Lock 简写X-Lock只有持有写锁的事物才能对数据进行写入操作。
    • 并且数据被加持写锁时其他事物不能写入数据,也不能施加读锁。但是其他不需要锁的事物可以正常读取到数据。
  • 读锁 Read Lock:
    • 也叫共享锁,Shared Lock 简称为 S-Lock 多个事物可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁,所以其他事物不能对该数据进行写入,但是仍然可以进行读取。
    • 如果数据只有一个事物加了读锁,那可以直接将其升级为写锁,然后写入数据。
    • 读锁 一个事物对数据加上了读锁,就表示这个数据不能被修改了。直到所有读锁被释放,或者是转化为了写锁。但是不影响其他事物读取被加锁的数据。
  • 范围锁 Range Lock:
    • 对于某个范围直接加排他锁,这个范围的数据不能被读取,也不能被写入。
    • 范围锁不是一批排它锁,排它锁是针对一批已存在的数据,而范围锁对于不存在于数据库中的数据也有效。
    • 范围锁案例:SELECT * FROM books WHERE price < 100 FOR UPDATE;
    • 具体数据库可以选择自己可能的方式去实现范围锁,以达到进一步的细分功能或提升性能等目的。例如表锁、行锁、页锁、间隙锁、后码锁

2.3.3 本地事物的四种隔离级别的实现

利用如上述几种锁实现下面的隔离级别,不同的数据库会有自己不同的实现,甚至是自己不同的锁,这里只是以ARIES理论来介绍。如果所有数据库的实现都一样,那也没必要有市面上这么多种数据库了。

可串行化 Serializable

  1. 这是最高的隔离级别
  2. 不考虑性能的话,对事物所有读写的数据,都加上读锁、写锁、和范围锁 就能实现串行化。
  3. 隔离程度越高,并发能力就越低,所以厂商一定会提供串行化之外的隔离级别供用户选择。

可重复读 Repeatable Read

  1. 可重复读的意思就是对事物涉及的数据,整个周期都施加读锁和写锁。这样事物涉及的数据,在加锁期间就无法被修改。事物结束前,读取的数据都是一致的。
  2. 可重复读对比可串行化,弱化的地方在于**幻读问题,**因为没有范围锁,假设事物A在不同时间查询或修改相同的范围数据,如果此时事物B修改了范围内的数据 事物A的两次查询或就可能会有不同的结果。这就是事物A被事物B影响,隔离性遭到破坏的表现。

读已提交 Read Committed

  1. 读已提交是指在事物执行的过程中,对同一行数据的两次查询得到了不同的结果。
  2. 例如事物A 第一次查余额是90,事物B在此过程中修改了价格为100,事物A第二次查询发现数据发生了改变,变成了100。这也是隔离性被破坏的表现!
  3. 读已提交出现这种情况,就是事物A读取数据时未对数据施加全周期的读锁,事物A读取完数据就释放了读锁,此时事物B施加写锁修改完数据又释放了,事物A后续再施加读锁读取就发现数据已经发生了变化。

读未提交 Read Uncommitted

  1. 会对事物涉及的数据只加全周期的写锁,但是完全不加读锁
  2. 读未提交比读已提交弱化的地方在于脏读问题,是指一个事物执行过程中读取到了另一个事物未提交的数据。
  3. 如果读取数据不加读锁的话,读取到的数据可能就是被别的事物施加了写锁的未提交的数据。
  4. 举例:事物A 修改价格 80->100 事物A未完成,写锁未释放。此时事物B尝试读取价格,隔离级别如果是读未提交那么事物B不加锁,直接读取到了事物A 未提交的数据100元! 此时发生了**脏读。**如果隔离级别是读已提交,那么事物B读取价格就需要先加写锁,此时写锁未释放所以事物B会被阻塞,在事物A提交后才能读取,就不会发生脏读。

更低的级别:完全不隔离,事物完全不加锁

  1. 读未提交会有脏读问题,不会有脏写 Dirty Write问题。但是完全不加锁,就会有脏写的问题。完全不隔离还会导致第一类丢失更新的问题,就是事物A回滚时,使得事物B已提交的数据被修改。
  2. 出现脏写问题,就已经连事物的原子性都无法保证了。所以一般隔离级别都不会包括他。

总结 不同隔离级别以及幻读、脏读等问题都只是表面现象,它们是各种锁在不同加锁时间上组合应用所产生的结果,锁才是根本的原因。

2.3.4 MVCC 无锁的隔离场景优化方案

MVCC 全称是 Multi-Version Concurrency Control 多版本并发控制。

MVCC是一种无锁的隔离场景优化方案
在上面隔离性被破坏的场景中(幻读、可不重复度、脏读等) ,都是一个事物读取数据过程被另一个更新数据的事物影响而破坏了隔离性。针对这种 “一个事物读取,另一个事物写入” 的隔离场景,可以引入MVCC作为一种无锁的优化方案。主流的商业数据库都采用了这种方案。
MVCC的基本思路

  1. MVCC的"无锁"是特指读取数据时,不需要加锁。
  2. MVCC的基本思路是对数据库的任何修改都不会覆盖之前的数据。而是产生一个新版本副本与老版本共存,以此达到读取时可以完全不加锁的目的。
  3. 新版本和老版本,可以理解为每一行记录都有两个看不见的字段,CREATE_VERSION和DELETE_VERSION,这两个字段记录的都是事物的ID。这里事物的ID是一个全局严格递增的数值。
  4. 数据被插入时:CREATE_VERSION记录插入数据的事物ID
  5. 数据被删除时:DELETE_VERSION记录删除数据的事物ID
  6. 数据被修改时:将修改视为“旧数据删除、新数据新增”则原有数据的。DELETE_VERSION和新数据的CREATE_VERSION为本次修改数据的事物ID。

MVCC优化事物隔离的场景

  • 隔离级别是可重复读:总是读取CREATE_VERSION 小于等于当前事物ID的记录,如果有多个就取事物ID最大的一个。这样事物A在读取数据时,事物B更新了数据产生了新的事物ID的CREATE_VERSION记录也不会被读取,事物A仍然读取的是其事物开始时的数据。这个数据不会被更改,天然不需要加锁。
  • 隔离级别是读已提交:每次读取最新的版本即可,这样每次都是读取到最后Commit的数据。

可串行化和读未提交用不上MVCC

  1. 串行化的目标是阻塞其他事物的读取和写入,MVCC是做读取时无锁优化的,自然是用不上。
  2. 读未提交 是需要直接读取未提交的数据,这种场景下直接修改原始数据即可,无需版本字段。

写入+写入的场景下MVCC无能为力
MVCC针对的是“读+锁”场景的优化,对于“写+写”的场景加锁几乎是唯一可行的解决方案。

2.3.5 乐观加锁和悲观加锁

一般来说提到的锁都是悲观锁(Pessimistic Locking)数据库认为需要先加锁再访问数据,不然肯定会出问题。而乐观锁策略(Optimistic Locking)认为竞争是偶然情况,没有竞争是普遍情况,应该一开始不加锁出现竞争时在补救。这种思路是 (Optimistic Concurrency Control,OCC)“乐观并发控制”
乐观锁和悲观锁的性能优劣主要看并发竞争的剧烈程度,如果竞争剧烈乐观锁反而更慢。

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

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

相关文章

基于高精度三维机器视觉的汽车曲轴无序抓取系统应用

Part.1 行业背景 汽车产业的高速发展&#xff0c;对零部件自动化生产提出了更高要求。随着汽车销量的水涨船高&#xff0c;传统的手工生产模式已经难以满足大批量生产的需求&#xff0c;自动化生产是必然趋势。 曲轴是汽车发动机的关键组件之一&#xff0c;生产过程复杂&#…

【MySQL】如何速通MySQL(4)

&#x1f4cc;前言&#xff1a;本篇博客介绍如何速通MySQL的第四篇&#xff0c;主要介绍Mysql中主要的基础的入门&#xff0c;学习MySQL之前要先安装好MySQL&#xff0c;如果还没有安装的小伙伴可以看看博主前面的博客&#xff0c;里面有详细的安装教程。或者看一下下面这个链接…

Linux(centos )防火墙常见操作

1、查看防火墙当前状态 systemctl status firewalld 2、开启防火墙 systemctl start firewalld 3、关闭防火墙 systemctl stop firewalld.service 4、如果报错&#xff1a;-bash: firewall-cmd: command not found&#xff0c;可能是没有安装 firewall。安装命令&#xff1a…

处理错误 Xcode 编译找不到文件 libarclite_iphonesimulator.a

处理错误 Xcode 编译找不到文件 libarclite_iphonesimulator.a 视频 https://youtu.be/ZBMFs2PwkB4 错误描述 Error (Xcode): File not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.aEr…

双非硕士-美国联培-马普所博士后-985系主任的逆袭之路

本科和硕士都是双非学校&#xff0c;博士期间曾有美国联合培养经历&#xff0c;毕业后到德国马普所从事博士后研究。现任985高校特聘教授、博/硕士生导师&#xff0c;系主任。知识人网小编特刊介绍李志明博士的逆袭之路。 随着国内就业压力的增大&#xff0c;高校招聘教师也呈现…

element 设置 table中的按钮权限

子组件 <template><!-- 二次封装表格&#xff0c; 仅支持单选 :style"{ height: height }"--><div class"self_table"><el-table:data"tableData"style"width: 100%"v-loading"loading"stripeselecti…

[游戏开发]Unity随机网格中空位置_二叉树

[目录] 0. 前言1. 简单随机2. 可用位置内随机3. 二叉树权重随机&#xff08;1&#xff09;分区域随机&#xff08;2&#xff09;设置权重均衡概率&#xff08;3&#xff09;二叉树缓存权重&#xff08;4&#xff09;利用二叉树随机&#xff08;5&#xff09;优缺点 4. 测试对比…

简要介绍 | Backbone与Baseline的区别

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对Backbone和Baseline进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 Backbone与Baseline的区别&#xff1a;从神经网络到性能基准 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来…

大厂测试员是如何编写测试用例呢?

一、测试用例是软件测试的核心 软件测试的重要性是毋庸置疑的。但如何以最少的人力、资源投入&#xff0c;在最短的时间内完成测试&#xff0c;发现软件系统的缺陷&#xff0c;保证软件的优良品质&#xff0c;则是软件公司探索和追求的目标。每个软件产品或软件开发项目都需要…

【活动总结】0617COC深圳社区首场线下AI技术沙龙活动最强总结

文章目录 活动的发起活动的宣传活动的进行活动的收尾活动的总结活动的致谢更多展望友情链接 就在2023年6月17日&#xff0c;CSDN COC 深圳城市开发者社区&#xff0c;在深圳大学组织了一次以【智能未来 —— 人工智能与城乡规划的交叉对话】为主题的线下沙龙活动&#xff0c;活…

基于spring boot的JsonSerializer 业务内容国际化

说起国际化&#xff0c;真的是老生常谈了。后端有各种i18n的依赖组件&#xff0c;springboot本身也支持i18n的设置&#xff0c;前端vue也有i18n的设置&#xff0c;这些常规操作就不提了&#xff0c;大家可以去搜索其他博客&#xff0c;写的都很详细。 本篇博客主要写的是业务内…

5大技巧,实现视频号预约直播人数暴涨!

两个体量相当的视频号&#xff0c;为什么别人的直播间人数过万&#xff0c;而自己的直播间却寥寥无几&#xff1f;这其中有一个非常重要的原因&#xff0c;就是预约直播的工作没有做好。 通常情况下&#xff0c;视频号直播预约人数和最终场观呈现1:10的比例&#xff0c;换言之…

聊聊Redis中的跳跃表

Redis 大家项目中应该都用过&#xff0c;哪怕没有分布式锁、幂等校验的一些逻辑使用场景&#xff0c;缓存数据这个大家肯定都用过吧&#xff1f;最简单的key-value格式&#xff0c;直接存储String类型。 当然&#xff0c;针对越来越复杂的业务场景&#xff0c;后续也可能用到li…

合宙Air724UG Cat.1模块硬件设计指南--数字语音接口

数字语音接口 简介 数字音频接口DAI&#xff0c;即Digital Audio Interfaces&#xff0c;表示在板级或板间传输数字音频信号的方式。相比于模拟接口&#xff0c;数字音频接口抗干扰能力更强&#xff0c;硬件设计简单&#xff0c;DAI在音频电路设计中得到越来越广泛的应用。 特…

【学习日记2023.6.20】之 分布式事务_CAP定理_BASE理论_微服务集成Seata_Seata的四种事务模式_高可用架构模型

文章目录 1. 分布式事务问题1.1 本地事务1.2 分布式事务1.3 演示分布式事务问题 2. 理论基础2.1 CAP定理2.1.1 一致性2.1.2 可用性2.1.3 分区容错2.1.4 矛盾 2.2 BASE理论2.3 解决分布式事务的思路 3. 初识Seata3.1 Seata的架构3.2 部署TC服务3.2.1 下载3.2.2 解压3.2.3 修改配…

数据库系统概述——第七章 数据库设计(知识点复习+练习题)

&#x1f31f;博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 &#x1f99a;专栏&am…

p7付费课程笔记:jvm基础知识、字节码、类加载器

编程语言 演化&#xff1a; 机器语言->编程语言->高级语言&#xff08;java&#xff0c;c,Go,Rust等&#xff09; 面向过程–面向对象-面向函数 java是一种面向对象、静态类型、编译执行&#xff0c;有VM&#xff08;虚拟机&#xff09;/GC和运行时、跨平台的高级语言…

第二章 视觉感知与视觉通道(复习)

大纲 视觉感知 认知 视觉通道 色彩* 可视化致力于外部认知&#xff0c;也就是说&#xff0c;怎样利用大脑以外的资源来增强大脑本身的认知能力。 感知是指客观事物通过人的感觉器官在人脑中形成的直接反映 感觉器官&#xff1a;眼、耳、口、鼻、神经末梢 视觉感知就是客观事物通…

世界史上五个横跨亚欧非三大洲的超强帝国

古代地中海和西亚地区文明出现的很早&#xff0c;经济文化社会都比较先进&#xff0c;其中古埃及早在四千多年前就建立了庞大的帝国&#xff0c;给世人留下了不朽的金字塔&#xff1b;两河流域、希腊半岛也很早就出现了城邦制的国家&#xff0c;也创造了灿烂的文明。同时&#…

架构设计我们要注意什么?

这几天我正在做一个新项目的架构设计&#xff0c;关于动态流程引擎平台的搭建&#xff0c;涉及到了系统架构的设计&#xff0c;里面涉及了方方面面&#xff0c;所以就想着结合自己的实际经验&#xff0c;遇到的问题&#xff0c;以及自己的理解&#xff0c;为大家做一个简单的分…