数据库事务详解

概述

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。

  • ACID 事务具有4个基本特征,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID。
  • 隔离级别 ACID这4个特征中,最难理解的是隔离性。在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。4个隔离级别分别是:读未提及(READ_UNCOMMITTED)、读已提交(READ_COMMITTED)、可重复读(REPEATABLE_READ)、顺序读(SERIALIZABLE)。
  • 事务并发引起的问题 数据库在不同的隔离性级别下并发访问可能会出现以下几种问题:脏读(Dirty Read)、不可重复读(Unrepeatable Read)、幻读(Phantom Read)。

事务的思维导图

ACID

1. 原子性(Atomicity)

事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现两种状态之一。

  • 全部执行成功
  • 全部执行失败

任何一项操作都会导致整个事务的失败,同时其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成。

2. 一致性(Consistency)

事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。

比如:如果从A账户转账到B账户,不可能因为A账户扣了钱,而B账户没有加钱。

3. 隔离性(Isolation)

事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。

一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的。

隔离性分4个级别,下面会介绍。

4. 持久性(Duration)

事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。

事务隔离级别

1. 读未提及(READ_UNCOMMITTED)

读未提及,该隔离级别允许脏读取,其隔离级别是最低的。换句话说,如果一个事务正在处理某一数据,并对其进行了更新,但同时尚未完成事务,因此还没有提交事务;而以此同时,允许另一个事务也能够访问该数据。

脏读示例:

在事务A和事务B同时执行时可能会出现如下场景:

时间

事务A(存款)

事务B(取款)

T1

开始事务

——

T2

——

开始事务

T3

——

查询余额(1000元)

T4

——

取出1000元(余额0元)

T5

查询余额(0元)

——

T6

——

撤销事务(余额恢复1000元)

T7

存入500元(余额500元)

——

T8

提交事务

——

余额应该为1500元才对。请看T5时间点,事务A此时查询的余额为0,这个数据就是脏数据,他是事务B造成的,很明显是事务没有进行隔离造成的。

2. 读已提交(READ_COMMITTED)

读已提交是不同的时候执行的时候只能获取到已经提交的数据。 这样就不会出现上面的脏读的情况了。

不可重复读示例

可是解决了脏读问题,但是还是解决不了可重复读问题。

时间

事务A(存款)

事务B(取款)

T1

开始事务

——

T2

——

开始事务

T3

——

查询余额(1000元)

T4

查询余额(1000元)

——

T5

——

取出1000元(余额0元)

T6

——

提交事务

T7

查询余额(0元)

——

T8

提交事务

——

事务A其实除了查询两次以外,其它什么事情都没做,结果钱就从1000编程0了,这就是不可重复读的问题。

3. 可重复读(REPEATABLE_READ)

可重复读就是保证在事务处理过程中,多次读取同一个数据时,该数据的值和事务开始时刻是一致的。因此该事务级别进制了不可重复读取和脏读,但是有可能出现幻读的数据。

幻读

幻读就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。

时间

事务A(统计总存款)

事务B(存款)

T1

开始事务

——

T2

——

开始事务

T3

统计总存款(1000元)

——

T4

——

存入100元

T5

——

提交事务

T6

提交总存款(10100)

——

T7

提交事务

——

银行工作人员在一个事务中多次统计总存款时看到结果不一样。如果要解决幻读,那只能使用顺序读了。

4. 顺序读(SERIALIZABLE)

顺序读是最严格的事务隔离级别。它要求所有的事务排队顺序执行,即事务只能一个接一个地处理,不能并发。

事务隔离级别对比

事务隔离级别

脏 读

不可重复读

幻 读

读未提及(READ_UNCOMMITTED)

允许

允许

允许

读已提交(READ_COMMITTED)

禁止

允许

允许

可重复读(REPEATABLE_READ)

禁止

禁止

允许

顺序读(SERIALIZABLE)

禁止

禁止

禁止

4种事务隔离级别从上往下,级别越高,并发性越差,安全性就越来越高。 一般数据默认级别是读以提交或可重复读。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PingCAP的专栏

当 TiDB 遇上 Jepsen

Kyle Kingsbury 采用函数式编程语言 Clojure 编写的验证分布式系统一致性的测试框架,作者使用它对许多著名的分布式系统进行了“攻击”(一致性验...

3060
来自专栏向治洪

android混淆和反编译

混淆 Android Studio: 只需在build.gradle(Module:app)中的buildTypes中增加release的编译选项即可,...

2578
来自专栏代码GG之家

封装之路(四) BaseFragment BaseViewModel BaseModel

框架实时变更,一直在调整,也是自己的实践过程,继续奋斗了。估计大家对实现没啥兴趣,这节结束,后面直接去github地址看更新了,就不再开贴说了。当这个框架完成时...

21310
来自专栏lgp20151222

Maven常用命令

1022
来自专栏软件开发

HTML5 学习总结(五)——WebSocket与消息推送

B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为...

3808
来自专栏mukekeheart的iOS之旅

安卓调试问题集锦

1、在AndroidManifest.xml文件中修改项目的版本号,即设置android:versionCode和android:versionName时,当手...

24710
来自专栏我的博客

Nginx前端,apache后端获取真实IP

http://www.stderr.net/apache/rpaf/download/ 需要使用apxs命令(这个命令在httpd-devel,可以使用yum ...

3106
来自专栏施炯的IoT开发专栏

使用托管代码开发WINCE自带数据库

    《在Windows Mobile上使用WINCE自带数据库》中,讲述了在Windows Mobile上使用native code来开发WINCE自带数据...

2466
来自专栏凉城

Emlog加cdn获取不到真实IP的解决办法

1904
来自专栏运维一切

ceph mon自行shutdown故障记录 原

主要在这个“reached critical levels of available space on local monitor storage”,如果mon...

811

扫码关注云+社区

领取腾讯云代金券