前言
如何控制并发是数据库领域中非常重要的问题之一,MySQL为了解决并发带来的问题,设计了事务隔离机制、锁机制、MVCC机制,用一整套机制来解决并发问题,本文主要介绍事务隔离机制。
一、什么是数据库事务
事务transaction(简写tx),在数据库中,事务是指一组逻辑操作,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与结束之间执行的全部数据库操作组成
。
事务具有以下4大特性,简称ACID:
1、原子性(A
tomicity)
事务是一个原子操作单元,是不可分割的最小工作单元,就像化学中的原子,其对数据的修改,要么全都执行,要么全都不执行
。
2、一致性(C
onsistent)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态。
一致性也称作是完整性,就是说事务的执行不能破坏数据库的一致性,在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性
。
3、隔离性(I
solation)
数据库提供一定的隔离机制,当多个事务并发访问时,保证事务在不受外部并发操作影响的“独立”环境执行
,当然了,不同的隔离级别决定了有多“独立”。
4、持久性(D
urable)
事务完成之后,它对于数据的修改是永久性的
,即使出现系统故障也能够保持。
小结:原子性,持久性大家基本都能秒懂,隔离性也还好大家稍微想想都能理解,就是接下来要讲的隔离级别,但对一致性很多人被官方概念绕住了,其实就是在多事务并发时要保证数据的一致和完整,不理解的话先看下面的问题。
二、事务并发带来的4类问题
1、脏读(Dirty Reads) 事务A读取到了事务B修改但尚未提交的数据,然后事务B回滚了,因此事务A基于此数据做的操作都是无效的,就是读到了“脏”数据(实际上不应该存在的数据),所以叫脏读。
2、脏写或丢失更新(Lost Update)
第一类丢失更新:撤销rollback
一个事务时,把其他事务已经提交更新的数据回滚
掉了。
第二类丢失更新:提交commit
一个事务时,把其他事务已经提交更新的数据覆盖
掉了。
3、不可重复读(Non-Repeatable Reads) 在事务A中,按相同的条件执行查询过的sql,返回结果发生了修改或被删除了,这种现象就叫做“不可重复读”。
4、幻读(Phantom Reads) 在事务A中,按相同的条件执行查询过的sql,返回结果中有新数据(是其它事务插入的),就好像发生了幻觉一样,这就叫“幻读”。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改或删除,幻读侧重于新增。就这个结论网上很多博主写的是
不可重复读侧重于修改,幻读侧重于新增或删除(包括一些知名博主),大家请注意删除不属于幻读,我会在第四段演示时求证。另外后面我会单独安排一篇介绍MVCC机制,到时你自然会明白这里的原因。
三、事务4种隔离级别
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些是在事务内和事务间可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
每种隔离级别可能出现的问题如下:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(RU) | 可能 | 可能 | 可能 |
读已提交(RC) | 不可能 | 可能 | 可能 |
可重复读(RR) | 不可能 | 不可能 | 可能 |
串行化(Serializable) | 不可能 | 不可能 | 不可能 |
1、读未提交(Read uncommitted,RU)
事务中的修改,即使没有提交,对其他事务也都是可见的,由于可能造成脏读,所以在实际应用中一般很少使用。
2、读已提交(Read committed,RC)
事务A修改并提交的数据才会对其它事务可见,所以解决脏读的问题。大多数数据库系统的默认隔离级别都是读已提交(像Oracle、PostgreSQL、SqlServer,但Mysql不是)。
3、可重复读(Repeatable read,RR) Mysql默认的事务隔离级别。它保证了在同一个事务中多次读取相同记录的结果是一致的,所以解决了脏读和不可重复读问题,但未彻底解决幻读。
4、串行化(Serializable)
可串行化是最高的隔离级别。它通过强制事务串行执行,避免了前面所说的脏读,不可重复读和幻读问题。简单来说,可串行化会在读取的每一行数据上都加上锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑用该级别。
四、Mysql演示4种隔离级别
在MySQL中,InnoDB引擎支持事务,MyISAM引擎不支持事务,所以本文实验的测试环境:Windows 10 MySQL5.7 InnoDB。
Mysql5.7可以通过命令select @@tx_isolation;
语句来查看:
mysql> select @@tx_isolation;
-----------------
| @@tx_isolation |
-----------------
| REPEATABLE-READ |
-----------------
设置4种隔离级别的命令:
代码语言:javascript复制set tx_isolation='read-uncommitted';
set tx_isolation='read-committed';
set tx_isolation='repeatable-read';
set tx_isolation='serializable';
开始事务:
代码语言:javascript复制begin;
提交事务:
代码语言:javascript复制commit;
回滚事务:
代码语言:javascript复制rollback;
1、读未提交(RU)
代码语言:javascript复制set tx_isolation='read-uncommitted';
select @@tx_isolation;
begin;
验证脏读
2、读已提交(RC)
代码语言:javascript复制set tx_isolation='read-committed';
select @@tx_isolation;
begin;
验证解决脏读,存在不可重复读
验证幻读
3、可重复读(RR)
代码语言:javascript复制set tx_isolation='repeatable-read';
select @@tx_isolation;
begin;
验证解决脏读和不可重复读
上面说的不可重复读侧重于修改或删除
,求证请看下面的截图,
验证幻读 Mysql的RR级别在一定程度上解决了幻读问题,但不够彻底,至于为什么这么说?还是那句话,得深入理解MVCC机制,这个会单独安排一篇,敬请期待!
4、串行化(Serializable)
代码语言:javascript复制set tx_isolation='serializable';
select @@tx_isolation;
begin;
如果长时间阻塞,最后会锁等待超时,抛出异常:ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 换成是在事务A执行,结果也是一样会阻塞,直到其它事务完成或超时抛出同样的异常。 对于update也是同样的道理,详细如下图:
总结
通过本文我们已经详细说明了:
- 事务4大特性:ACID
- 事务并发带来的4类问题:脏读、脏写、不可重复读、幻读
- 事务的4种隔离级别:读未提交、读已提交、可重复读、串行化
- Mysql提供的4种隔离级别演示
剩下的MySQL锁机制和MVCC机制,我们下文见!如果感觉不错,请关注我分享更多干货:天罡gg 最好的关系是互相成就,大家的「三连」就是我创作的最大动力!
参考文章: 什么是事务? 三分钟图解事务隔离级别,看一遍就懂 MySQL事务隔离级别详解 MySQL的四种事务隔离级别 透彻解读mysql的可重复读、幻读及实现原理 【MySQL (三) | 五分钟搞清楚MySQL事务隔离级别】