文章目录

  • 事务
  • ACID
  • 并发带来的隔离问题
    • 幻读(虚读)
    • 不可重复读
    • 脏读
    • 丢失更新
  • 隔离级别
    • Read Uncommitted (读未提交)
    • Read Committed (读已提交)
    • Repeatable Read (可重复读)
    • Serializable (可串行化)
  • 事务的使用
  • 事务的实现
    • Redo
    • undo

事务

事务指逻辑上的一组操作。

我们在 MySQL 存储引擎 | MyISAM 与 InnoDB 中提到,MyISAM引擎 并不支持事务,所以本文内容主要与 InnoDB引擎 相关。

这篇博客写事务也写得很好:我以为我对Mysql事务很熟,直到我遇到了阿里面试官


ACID

谈到事务,那肯定少不了ACID的特性,ACID是以下几个单词的缩写:

原子性(atomicity):

事务是一个不可分割的工作单位,对数据的修改要么全部执行成功,要么全部失败。

举个例子:事务A中要进行转账,那么转出的账号要扣钱,转入的账号要加钱,这两个操作都必须同时执行成功,从而确保数据的一致性。

一致性(consistency):

事务操作前与操作后数据库的状态始终一致。

如何理解呢?就好比我们此时有用户A和用户B,他们的余额分别为300元和700元,此时两人总金额为1000元。此时若是用户B向用户A转账200元,则两者的此时都有500元,总金额还是1000元。

也就是说,无论我们两个怎么转账,总金额它只会是1000,既不会多,也不会少。这就是事务操作前后的状态始终一致。倘若钱多了或者少了,都代表着事务将数据库从一种状态变为了另外一种状态,此时就不再符合一致性了。

隔离性(isolation):

隔离性指的是每个读写事务的对象之间相互隔离,即该事务提交前对其他事务都不可见。

持久性(durability):

持久性指的是事务一旦提交,这个事务的状态会被持久化到数据库中。 即使发生了服务器宕机的事故,数据库也能成功的将数据给恢复。

但是需要注意的是,只能保证数据库本身发生的问题后可以恢复,但并不是事务提交后所有变化都是永久的,倘若是由于外部原因如:RAID卡损坏、天灾人祸导致数据库发生问题,那么即使事务提交了,也可能会丢失。

基于上述原因,持久性只能保证事务系统的高可靠性,而无法保证其高可用性。

总结:

原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终的目的。


并发带来的隔离问题

幻读(虚读)

幻读指 在同一事务中,用同样的操作读取两次,得到的记录数却不一样(针对 insert 操作)。 举个例子:

  • 第一个事务对表中的所有数据行进行修改;
  • 同时,第二个事务向表中插入了一行。这样也就导致了操作第一个事务的用户发现表中还有没修改的数据行,像发生了幻觉一样。


明明在 会话A 的第一次查询中,大于 2 的数只有行只有一行,而由于 会话B 插入了新行后,对于 会话A 而言就凭空多出来了一行,像出现了幻觉一样。


不可重复读

不可重复读指的是在一个事务中多次读取同一行数据,但是多次读取的数据却不一样(针对 update 操作)。导致这一问题的主要原因就是一个事务读取到了其他事务已提交的数据

例如:

  1. 账户1中有300元,账户2中有500元
  2. 事务A读取账户B的内容,里面显示有500元
  3. 事务B将账户1的300元全部转给账户2,并提交事务
  4. 事务A再次读取账户B,此时里面有800元。

由于其他事务的干扰,对于事务A来说,两次读取的金额都不一样。

因为不可重复读读到的是已经提交的数据,由于其本身并不会带来很大的问题,所以大部分数据库厂商都会允许这种情况的发生。


脏读

脏读即一个事务读取到了另外一个事务中未提交的数据,也就是可能因为其他事务对数据进行修改或者回滚导致的问题。


会话B 在第一次查看时表中只有一条数据,但是在第五阶段中 会话A 向表中插入了另一条数据(但还未commit【提交】),这就导致了 会话B 在读取的时候得到的结果就不再一样,因为它读取到了脏数据。

脏读的现象并不会经常发生,因为脏读发生的条件是需要事务的隔离级别为 READ UNCOMMITTED(读未提交),而大部分数据库的默认隔离级别都为 READ COMMITTED(读已提交)


丢失更新

丢失更新就是一个事务的更新操作会被另外一个事务的更新操作所覆盖,从而导致数据的不一致。例如以下案例:

  1. 事务A行记录r 更新为 1,但是 事务A 并未提交;
  2. 同时,事务B行记录r 更新为 2事务B 也未提交;
  3. 事务A提交;
  4. 事务B提交。

此时由于 BA 的修改覆盖,导致 A 虽然提交,但是更新却丢失了,只剩下了 B 的更新。

但是在当前数据库的任何隔离级别下,都不会导致理论意义上的丢失更新问题,即使是隔离级别最低的 Read Uncommitted,也由于加锁保护,所以 事务B 的修改操作会被阻塞,直到 事务A 提交。


隔离级别

为了解决上述问题,MySQL中实现了以下四种隔离级别,隔离级别由低到高依次是:

  • 读未提交(READ UNCOMMITTED)
  • 读已提交 (READ COMMITTED)
  • 可重复读 (REPEATABLE READ)
  • 串行化 (SERIALIZABLE)

隔离级别越高,事务请求的锁也就越多,保持锁的时间也就越长。所以隔离性越强,并发的效率也就越低。


Read Uncommitted (读未提交)

在该隔离级别下,所有事务都可以看到其他未提交事务的执行结果,容易产生脏读问题。

在该级别下,虽然并发的效率最高,但是安全性完全没有得到保护,所以很少用于实际应用。


Read Committed (读已提交)

该隔离级别是大部分数据库默认的隔离级别,如 OracleSQL Server 等。该隔离级别下,一个事务只能看见提交了的事务所做的改变,容易产生不可重复读的问题。

虽然它还有,但不可重复读本身并不是一个大问题,所以为了兼顾到性能,大部分数据库都会容许这种问题的产生。


Repeatable Read (可重复读)

这是 MySQLInnoDB 默认的隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,容易产生幻读的问题。

InnoDB 可以借助 MVCC 中的 Next-Key Locking 的加锁方式来解决这个问题,详见本文。


Serializable (可串行化)

这是最高的隔离级别,通过强制事务进行排序,使事务之间不可能互相冲突,从而解决了其他隔离级别无法解决的幻读问题

由于其在每个读的数据行上加了共享锁,所以在该隔离级别下可能会导致大量的超时现象以及锁竞争


这四种隔离级别分别可能发生的问题如下图所示:


事务的使用

开启事务

START TRANSACTION
或者
BEGIN
(由于MySQL的数据分析器会自动将BEGIN识别为BEGIN...END,所以在存储过程中只能使用START TRANSACTION来开启事务)

提交事务

COMMIT

回滚事务

//回滚整个事务
ROLLBACK//回滚至某个保存点
ROLLBACK TO SAVEPOINT [保存点ID]

设置保存点

SAVEPOINT 保存点ID

删除保存点

RELEASE SAVEPOINT 保存点ID

查看隔离级别

// 可以看到 MySQL 的 InnoDB存储引擎 的默认隔离级别为可重复读
mysql> SELECT @@TRANSACTION_ISOLATION;
+-------------------------+
| @@TRANSACTION_ISOLATION |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

设置隔离级别

SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
// GLOBAL 也可以换成 SESSION,前者表示全局的,后者表示当前会话,也就是当前窗口有效。

PS:当设置完隔离级别后对于之前打开的会话,是无效的,要重新打开一个窗口设置隔离级别才生效。


事务的实现

  • 事务的持久性主要依靠 Redo log(重做日志)来完成。
  • 原子性、一致性则通过 Undo log(撤销日志)来完成。
  • 隔离性,则通过锁来完成。

先简单说说 Redo 和 Undo :

Redo/Undo机制: 将所有对数据的更新操作都写到日志中。

  • Redo log 用来记录某数据块被修改后的值,可以用来恢复未写入 data file 的已成功事务更新的数据。Redo 通常是物理日志,记录的是页的物理修改操作。
  • Undo log 是用来记录数据更新前的值,保证数据更新失败能够回滚。Undo 是逻辑日志,根据每行记录进行记录。

举个例子:

假如某个时刻数据库崩溃,当数据库重启进行 crash-recovery 时,就会通过 Redo log 将已经提交事务的更改写到数据文件,而还没有提交的就通过 Undo log 进行 回滚roll back


Redo

Redo log 由两部分组成:

  • 一是存在于内存中的 重做日志缓冲(redo log buff),由于存在内存中,所以其具有易失性。
  • 二是 重做日志文件(redo log file),其存在于硬盘中,所以是持久的。

Redo 主要通过 Force Log at Commit机制 来实现事务的持久性。

步骤如下:


为了确保日志写入文件中,每次将日志缓冲写入日志文件后,都会发起一次 异步操作(fsync)

为什么需要这个异步调用呢?

因为重做日志文件打开时并没有使用 O_DIRECT 选项,所以重做日志缓冲会先写入文件系统缓冲,为了保证其能够成功写入磁盘,必须发起一次异步调用。由于异步调用的效率取决于磁盘的性能,因此磁盘的性能决定了事务提交的性能,即数据库性能。


undo

undo 是撤销日志,其中保留了数据库各个版本的状态,我们可以借助 undo 逻辑地将数据库恢复到原来地样子。除了进行回滚之外, undo 的另一个作用就是实现 MVCC

首先看看 undo log 的生成流程:


每当事务发生变更的时候,都会伴随着 undo log 的产生,并且为了防止其丢失,undo log 会比数据先持久化到硬盘上。

由于 undo log 是逻辑日志,所以其中记录的都是对于数据库的操作指令。而事务的回滚,其实也就是根据这个操作来进行一个逆向操作。如下面几种:

  • 当执行一个 insert 指令时,其逆向指令为 delete
  • 当执行一个 delete 指令时,其逆向指令为 insert
  • 当执行一个 update 指令时,其逆向指令为 update


原子性就是借助以上机制实现,倘若事务中的某一个步骤未能成功完成,则借助 undo log 中存储的记录来回滚到事务的最原始状态,即一个失败全体失败。

而至于一致性,则主要依靠上述的其他三种特性来实现,也就是说一致性是目的,而原子性、隔离性、持久性则是数据库实现一致性的手段,只有满足这三个性质,才能够保证一致性。

MySQL 事务 | ACID、四种隔离级别、并发带来的隔离问题、事务的使用与实现相关推荐

  1. MySQL 事务 :ACID、并发带来的问题、事务的隔离级别、事务的实现

    文章目录 ACID 原子性 一致性 持久性 隔离性 并发带来的隔离问题 幻读(虚读) 不可重复读 脏读 丢失更新 隔离级别 Read Uncommitted (读未提交) Read Committed ...

  2. mysql隔离级别 简书_数据库事务和四种隔离级别

    什么是事务 事务(Transaction):访问并可能更新数据库中各种数据项的一个程序执行单元(unit),它通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起 ...

  3. mysql四种事务级别_【MySQL 知识】四种事务隔离级别

    摘要:本篇文章主要是为了对MySQL的四种事务隔离级别的介绍.为了保证数据库的正确性与一致性,数据库事务具有原子性(Atomicity).一致性(Consistency).隔离性(Isolation) ...

  4. js hbs mysql_实例分析MySQL下的四种事务隔离级别

    数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据. 提交读(Read Committed):只能读取到已经提交的数据, ...

  5. MySQL事务的四种隔离级别,mysql中的不可重复读和幻读的区别,Repeatable read可重复读隔离级别下怎么不存在幻读问题?

    1. 事务的隔离级别 1.1 read uncommited:读未提交.一个事务读到了另一个事务未提交的脏数据,称之为脏读. 1.2 read commited:读已提交.解决了脏读问题,但当前事务两 ...

  6. 数据库事务的四种隔离级别

    文章目录 1. 引言 2. 事务隔离级别 2.1 事务四种隔离级别 2.2 查看隔离级别 3. 脏读/幻读/不可重复读 3.1 脏读 3.2 不可重复读 3.3 幻读 4. 总结: 1. 引言 &qu ...

  7. 事务的四种隔离级别(一)Read uncommitted

    背景知识 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别. 之所以提出事务隔离级别,是因为同一个应用程序中的多个事务或不同应用程序中的多个事务在同一个数据集上并发执行时, 可能会 ...

  8. MySQL不同隔离级别并发测试分析

    MySQL不同隔离级别并发测试分析 背景 事务 基于锁的并发控制 MVCC 测试方法 用例与分析 测试结果 用例分析 总结 背景 事务 事务是数据库执行过程中的一个逻辑单位,由一个有限的数据库操作序列 ...

  9. 什么是事务以及事务的四种特性

    什么是事务以及事务的四种特性 事务(Transaction),一般是指要做的或所做的事情.在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务应该具有4个属性:原子性 ...

最新文章

  1. servlet工作原理_Servlet 生命周期、工作原理
  2. WPF MultiSelect模式下ListBox 实现多个ListBoxItem拖拽
  3. 【Machine Learning实验2】 Logistic Regression求解classification问题
  4. MySQL删除普通用户
  5. MY MOBILER v1.23 - 类似SOTI Pocket Controller的免费工具
  6. linux下重装mysql_Linux下安装mysql
  7. POJ 1001 Exponentiation (记第一道Java水过的题)
  8. windows 2008 R2操作系统上使用iis服务运行php和mysql数据库的网站遇到的验证码不显示问题?...
  9. 28. Element nodeValue 属性
  10. 超好用的代码格式化工具Astyle使用
  11. 20140711 loop-II 调和数列
  12. 移动端+京东移动端首页制作
  13. 华为方舟编译器官网正式上线,写一篇你应该知道的科普文章
  14. Win7下使用wubi.exe安装Ubuntu系统
  15. 数据分析师有哪些等级
  16. java判断版本号大小,比较版本号大小
  17. ORA-01779: 无法修改与非键值保存表对应的列
  18. zookeeper 删除节点时报错java.io.IOException: Packet len4272892 is out of range!
  19. 绘图软件推荐——Diagram Designer
  20. Hu距(Hu Moments)图像距介绍

热门文章

  1. html css 前端实现消息提醒数_自学的福音,web前端学习全套视频教程+最新学习思维导图都在这里...
  2. inside uboot (六) DRAM芯片的控制线及时序
  3. Qt UDP的初步使用
  4. A20 文件系统预装APK
  5. ARM指令 LDR 和 ADR的一些区别
  6. aliyun centos6 安装mysql_阿里云CentOS6.8安装MySQL5.6
  7. 外架小横杆外露长度规范要求_安全文明施工规范
  8. 大数据-----软件开发模型(详细讲解)
  9. Office Web Apps安装部署(二)
  10. 【转】2.4SharePoint服务器端对象模型 之 访问网站和列表数据(Part 4)