您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 订阅
  捐助
数据库事务简介- 所谓事务
 
作者:人世间
   次浏览      
2020-7-6 
 
编辑推荐:

本文主要介绍了事务的概念、事务的特性、事务状态、事务管理等内容,详情请看下文。
本文来自简书,由火龙果软件Anna编辑、推荐。

事务的概念

事务是一系列操作的集合,从宏观角度,事务是访问数据库的一个逻辑单元(集合),其微观视角可以抽象为对数据的读和写(一系列操作)。

例如银行转账,Bob给Smith转账100元,转账的操作为

锁定Bob账户

锁定Smith账户

读取Bob的账户,查看是否有100元,Bob账户减少100元,更新Bob的账户

Smith账户加上100元,更新Smith的账户

解锁Bob账户

解锁Smith账户

这一些列操作集合为一个事务单元,而其本质上就是对Bob和Smith数据项的读和写。除此之外,常见的事务还有很多,例如

创建一个数据表

执行一条select查询语句,读取一行记录

创建一个数据库索引

插入一条数据,删除一条数据

......

上面所罗列,都是对数据库的一些基本操作,或基本操作的集合,这些都属于事务,或称之为事务单元。本质上都是对数据库的读写操作。

有人可能不理解,为什么没有 Begin Transaction 声明之后的 SQL 语句也是事务。SQL 的标准规定了一条 SQL 语句被执行,就隐式的开启了一个事务,当 SQL 语句执行完之后也自动的进行 Commit。

如果一个事务要执行多条 SQL 语句,就必须关闭单独的SQL语句的自动提交,显示的使用 Begin Transaction ... Commit/Rollback声明。当执行到 Commit 或者Rollback就结束一个事务。显式使用了Begin Transaction 的一组 sql 语句集合为事务单元。

事务的特性

提到事务,很多书籍或者 Blog 都会搬出事务的 ACID。ACID 是事务的基本特性

原子性(Atomicity)

一致性(Consistency)

隔离性(Isolation)

持久性(Duration)

诚然,ACID 特性是数据库事务的基石,然而到底 ACID 是何意,单从概念上很好背,然后理解却不是一件容易的事情。主要原因是这几个概念的命名的语义是单只在数据库语境中的意义,并且初看几个特性视乎又是相互有交集。我们暂时不必过于纠结他们的定义,而是从数据库的实现和使用角度来慢慢的理解。

原子性

如何理解原子性呢?在化学中,物质都是由原子构造,早期的化学家有一个想法,将物质进行切分,就像切蚯蚓一样。但是不管怎么切,每次都会变得更小。那么切到什么程度就不能切了呢?最后认为原子是最小的单位,即不能再进行分割。因此原原子表示不可分割, 其实原子还是可以分割为自由电子和原子核。原子性可以理解为“不可分割”,原子核和自由电子是不可分割的一个整体。

套用在数据库系统中,原子性就是组成事务的读写操作指令的集合是一个整体,不可分割。这些事务单元的一系列操作命令,要么全部执行,要么全部不执行(回滚)。

宏观上来看,事务要么成功,要么就是失败,不能有其他状态。例如 Bob 给 Smith转账的 case 中,只有两种结果,转账成功(Bob 账户少 100,Smith 账户多100),或者转账失败(权当事务没有发生过)。不能存在,Bob 转出去了,而Smith 账户却没有收到钱的中间状态。

因为操作指令不能分割,就不存在有的指令执行成功,有的未执行或执行失败的中间状态。

这里的原子性强调的是从事务单元的宏观角度来看,事务成功或者失败。微观上来看就是事务可以恢复,恢复到事务尚未发生的状态。

一致性

一致性也是一个颇为让人费解的定义。顾名思义,一致性强调的就是一样。CAP理论也有一致性,在分布式系统中一致性只各个节点的数据都一样。数据库的一致性含义却是数据库从一个正确的状态,转变成另外一个正确的状态,这里更多的强调是正确性,更像是业务要求,业务又属于应用层软件所要关系的特性,数据库此时的角色略显尴尬。

之所以会有不一致,原因就是数据库在执行事务单元的时候是并发操作。即事务单元的指令是相互交叉并发执行,如果执行顺序不对,会有可能带来业务属性的错误。导致事务执行结束之后,发现数据库是不一致的(错的)。

如果是串行的执行,那么肯定就不会有一致性问题。因此一致性也可以这么理解,就是并发执行的事务,其结果和串行执行的结果一致(正确),那么就说这个并发事务符合一致性。

例如上面的转账系统,假设 Bob 和 Smith 初始都有100块,系统总共有 200 块,Bob 给 Smith 转账后,系统还是 200 元。如果数据库线程操作事务的时候,未对Bob 和 Smith 账户加锁。

T1 事务表示 Bob 给 Smith 转账,当 Bob 账户减少 100 元,尚未给 Smith 账户加上100元的时候,此时其他数据库线程 T2 读取这个状态(其他事务并发执行),那么T2 读取到一个不正确的状态(此时的系统却只有100元),即数据库不一致了。因为在事务执行完毕之后,根本不存在 Bob 没有钱,Smith 仅有 100 元的情况。

这种状态是业务所不能接受的,却是数据库并发调度产生的。因此为了保证正确,数据库需要做到一致性。如何做到呢,不一致是因为中间状态被其他事务看到了,显然禁止读取中间状态就保证了一致性。

因此,数据库一致性可以理解为,在事务开始和结束之间的中间状态不会被其他事务所看到。实现一致性最简单办法就是,让数据库事务的指令像队列一样,有时序的串行执行。那么中间状态就不会被其他事务看到了。

可是这样的实现方案,一眼就能看出数据库的并发性能将会及其低下。并发调度的事务,其结果和串行调度的一致,那么也符合一致性的约束。为了保证一致性,又为了提高并发性能,数据库系统做了取舍,即通过隔离性来平衡。

隔离性

从上面的例子可以看出,串行执行数据库事务读写操作时,一定会保证数据库的一致性。然而很多时候,不同的线程的读写操作的未必是同样的数据。Bob 在给 Smith 转账的时候,Tom 也可能给 Green 转账。他们两个事务完全可以并行执行,相互之间不受影响。因此我们可以并发调度这两个事务进行,宏观上看他们就是同时进行的。隔离性就是指并发调度的事务,相互之间没有影响,事务都任务只有自己在执行。

隔离性的本来要求一组对数据库的并发修改互相不影响,可是实际上,像上面不操作同样数据的时候就不会有影响,而操作相同数据元素的时候,就可能产生冲突,冲突就会导致不一致。因此就需要区分哪个修改优先级更加高,而高优先级的修改应该覆盖掉低优先级的修改。

有的应用场景对性能要求比较高,反而对一些不一致错误业务上可以接受。此时就会出现允许这种不一致。这几种不一致的情况是:

脏读

不可重复读

幻读

针对这几种不一致的”错误“,数据库使用了隔离级别来描述。本质上是对并发调度的处理方式进行的三种实现。所谓隔离就是隔离不一致的错误。隔离级别如下:

× 表示不能隔离,会出现此种不一致错误

√ 表示可以隔离,不会出现该不一致错误

关于三种不一致问题,将会在数据库并发控制里讨论

注意:在实现了mvcc 的 innodb 和 postgresql 的数据库对应的RR隔离级别,也不会出现幻读错误。

通过上面的表,可以看到,读取 Bob 给 Smith 中间状态的隔离级别为读未提交,假设转账回滚了,就发生了脏读,这种隔离级别不能隔离脏读。对于这三种隔离级别,后面的并发调度将会详细讨论。

由此可见,对于隔离性的理解,可以结合后面的并发调度进行认识,简而言之为:适当的破坏一致性来提升性能和并行读。

数据库系统要保证一致性,才能为应用层提供正确的业务逻辑,而为了提升并发读,在业务处理上做到正确性的保证,那么可以通过设置隔离级别提升性能,尽管这样会破坏数据库本身的一致性,而此时的一致正确交给应用层强保证,数据库只做低层次的保证。

持久性

数据库系统最后一个特性是持久性,这也是唯一一个字面意思很好理解的特性。持久性指的就是事务提交之后,就一定是在硬盘永久的存储,而不会丢失。虽然持久性比较好理解,可是实现却不简单,数据库系统通过undo,redo,undo/redo日志实现。即对数据库硬盘存储数据的时候,都是先写日志,再写存储。

通常,软件对数据的操作都在内存,内存数据是易丢失的。存储多数在外存(硬盘)。一个事务的提交操作包括内存和硬盘之间的交互。如下:

事务的处理在内存里进行,当事务进行提交的时候,实际上是把数据写入到内存的DB 缓冲区了,然后再将 DB buffer 的数据强制写入硬盘中。DB buffer 到 disk 之间的交互用 output 指令表示。对于不同的日志类型,Commit 和 output 的先后顺序也不一样。

Undo日志是在写了 commit 之后,再进行 output 操作,redo日志则相反,再进行output 操作,再写入commit 日志。当数数据库发生故障的时候,需要根据日志的规则进行事务的撤销和重做,保证在 commit 之后,数据一定要落盘。具体的原理和过程将会在故障处理的部分进行讨论。

事务状态

介绍了事务的 ACID 特性之后,想必这些概念还是有点模糊。没关系,后面我们会结合后面的数据库的故障恢复和并发处理来理解。事务是一系列操作命令的集合单元,那么在执行这些指令的时候,事务本身这个逻辑单元有一些状态,用于标识事务进行的程度。事务的状态机大致如下:

事务状态

执行了Begin Transition 之后,事务就进行了活动状态,如果刚执行第一个sql语句的时候,就出错了,那么事务就进入失败状态,最后会撤销事务进入终止状态。

当然也可以执行完所有 sql 语句。最后一个 sql 语句执行,就进入到部分提交,对数据的修改都写入到 DBbuffer 区里。此时要是发生故障,那么事务就会变成失败状态。当然如果正常提交,将 DB buffer 的数据写入到磁盘,那么事务就变成提交状态。

事务管理

事务的管理可以用下图简要的概括。

事务管理

当用户提交写的SQL命令的时候,首先将发送给事务管理器,后者进度并发调度处理,将命令发给查询处理器执行,同时也像日志管理器写入日志。

随后是将缓冲区的数据写入到数据库中,或者通过恢复处理器进行事务重做或者恢复。具体的恢复细节我们后面再讨论。

总结

事务是数据库系统的核心,是访问数据库的逻辑单元,这个逻辑单元是一条或者一系列操作读写指令的集合。事务具有ACID四个特性。

A 原子性指事务要么成功,要么失败,可以回滚。

C 一致性指事务从一个正确的状态转变成另外一个正确的状态,在事务开始和结束之间的中间状 态不会被其他事务所看到。

I 隔离性指并发执行的事务,不受别的事务的干扰,通过对一致性的适当破坏来提高并发性能,设置隔离级别隔离可能存在的一致性问题。

D 持久性指事务提交时候,一定能够写入磁盘,永久存在。

由此可见 AD 只要针对数据库的故障恢复,CI则是数据库并发调度的保证。接下来将会详细的介绍数据库的故障恢复和并发调度。

 

 

 

   
次浏览       
相关文章

基于EA的数据库建模
数据流建模(EA指南)
“数据湖”:概念、特征、架构与案例
在线商城数据库系统设计 思路+效果
 
相关文档

Greenplum数据库基础培训
MySQL5.1性能优化方案
某电商数据中台架构实践
MySQL高扩展架构设计
相关课程

数据治理、数据架构及数据标准
MongoDB实战课程
并发、大容量、高性能数据库设计与优化
PostgreSQL数据库实战培训
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]
 
最新文章
InfluxDB概念和基本操作
InfluxDB TSM存储引擎之数据写入
深度漫谈数据系统架构——Lambda architecture
Lambda架构实践
InfluxDB TSM存储引擎之数据读取
最新课程
Oracle数据库性能优化、架构设计和运行维护
并发、大容量、高性能数据库设计与优化
NoSQL数据库(原理、应用、最佳实践)
企业级Hadoop大数据处理最佳实践
Oracle数据库性能优化最佳实践
更多...   
成功案例
某金融公司 Mysql集群与性能优化
北京 并发、大容量、高性能数据库设计与优化
知名某信息通信公司 NoSQL缓存数据库技术
北京 oracle数据库SQL优化
中国移动 IaaS云平台-主流数据库及存储技术
更多...