MySQL事务的四个特征(ACID)以及隔离级别

发布于:2022-12-31 ⋅ 阅读:(348) ⋅ 点赞:(0)

首先感谢以下博主资源,附上链接:
http://www.zhai14.com/blog/strenghen-comprehension-on-dirty-read-and-phantom.html
https://zhuanlan.zhihu.com/p/150107974
https://blog.csdn.net/qq_38238296/article/details/88363017
https://www.cnblogs.com/xrq730/p/5087378.html

1.MySQL的四个特性(ACID)

InnoDB存储引擎还提供了两种事务日志:redo log(重做日志)和undo log(回滚日志)。其中redo log用于保证事务持久性;undo log则是事务原子性和隔离性实现的基础。

  • 原子性(Atomicity):原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。
  • 一致性(Consistency):所谓一致性是数据库处理前后结果应与其所抽象的客观世界中真实状况保持一致。这种一致性是一种需要管理员去定义的规则。管理员如何指定规则,数据库就严格按照这种规则去处理数据。如A给B转账500,A减少500,B增加500,总值不变。是由应用层代码实现的。
  • 隔离性(Isolation):当并发时,多个事务间互不干扰。隔离性由数据库的隔离级别决定。
  • 持久性(Durability):持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。

2.MySQL的四种隔离级别

请添加图片描述

  • Read Uncommitted(读未提交)
    在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(DirtyRead)
  • Read Committed(读已提交)
    读取已提交数据,不可重复读,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(NonrepeatableRead),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
  • Repeatable Read(可重复读)
    读已提交数据,可重复读。这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(PhantomRead)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion ConcurrencyControl)机制解决了该问题。
  • Serializable(可串行化)
    事务顺序执行,没有并行,完全杜绝幻读。这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争

3.事务并发遇到的几个问题

1.脏写(两个修改的事务)
有多种情况,在事务A修改数据提交前,事务B修改了数据,发现没生效,事务B就是脏写了。(以上4种隔离级别下,都不存在脏写情况,原因下面有)
列举以下两种情况:

  • 如下,事务B在事务A修改提交事务前,事务B先修改提交事务,然后事务A提交事务,事务A覆盖了事务B修改的数据。对事务B来说,发现自己修改的数据没生效,事务B就是脏写了。

请添加图片描述

  • 或者事务B先提交事务,然后事务A回滚,也会造成事务B脏写

注:
文上提到的4种隔离级别下,都不存在脏写情况。因为在这些隔离级别下,当两个事务A和B尝试去更新同一条数据时,假定A先更新数据,会对更新的数据行记录加上排他锁(也叫写锁,悲观锁),除非事务A提交或终止从而释放排他锁,否则事务B都是无法更新数据的。(设计数据密集型应用只是说读提交隔离级别一定可以杜绝脏写问题,并未提到读未提交隔离级别,经过实践,读未提交下事务B的更新操作也是需要等待事务A的排他锁释放,才得以执行)

2.脏读(一个读事务、一个修改事务)

  • 事务A修改数据后,但是还没有提交事务,此时被事务B读取到了数据,然后事务A回滚了,事务B就是脏读了,读到了无效的数据,脏数据。

请添加图片描述
示例:
事务A把小王的钱转了100给小明,但是还没有提交事务,小明登录自己的银行APP查看自己的余额,发现多了100。然后正准备提现,此时事务A回滚了。小明提现失败,再次查询发现没有了100大洋。小明很崩溃。

脏读演示:
首先把隔离级别改为读未提交(要重启命令提示符)

set global transaction_isolation ='read-uncommitted';

查看隔离级别

show global variables like '%isolation%';

如下所示,事务回滚,读的就是脏数据
在这里插入图片描述

3.不可重复读(一个读事务、一个修改事务)
一个事务中多次相同的查询,查到了不同的结果,就是不可重复读。

例子:事务A查询某值为5,事务B修改为8并提交事务,事务A再次查询时值变成了8,即为不可重复读。

4.幻读(一个读事务、一个新增事务)
在一个事务中使用相同的 SQL 两次读取,第二次读取到了其他事务新插入的行。

例子:事务A第一次查询到5条数据,事务B新增了3条数据并提交,事务A再次查询就变成了8条数据,这时事务A出现了幻读。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到