MySql(Innodb)事务隔离级别
事务将数据库从一个一致状态转换至另外一个一致状态,若某个事务看到了另外一个事务在状态转换过程中的中间态数据(不一致状态),将有可能导致另外一个事务的操作基于一个不一致的数据库状态,进而数据库失去一致性。事务隔离性主要用于处理数据库的并发访问问题。
ACID
回顾事务的ACID特性,ACID分别是一下四个词的缩写:
- Atomicity(原子性)
- Consistency(一致性)
- Isolation(隔离性)
- Durability(持久性)
事务隔离性
“隔离性还有其他的称呼,如并发控制(concurrency control)、可串行化(serializability)、锁(locking)等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事务都不可见,通常这使用锁来实现。当前数据库系统中都提供了一种粒度锁(granular lock)的策略,允许事务仅锁住一个实体对象的子集,以此来提高事务之间的并发度。”
简单的说,事务隔离性就是指在并发情况下,事务能够相互隔离,不彼此影响,避免一些“不良反应”。
事务并发
在并发状态时,如果不控制好事务,如果事务没有隔离性,会有哪些“不良反应”?
-
脏读(Dirty read):
- 事务 A 在操作数据时,把数据 a 改成 b,但是事务未提交;
- 此时数据 a 是之前的数据,是有效的。数据 b 未提交,是无效的,如果在事务处理期间发生错误,数据 b 会回滚到 a;
- 如果此时事务 B 访问了数据,得到的是 b,那么就发生了脏读,读到了“脏数据” b。
-
不可重复读(Unrepeatableread):
- 因为业务需要,事务 A 在处理事务过程中,需要多次读取数据 a=1,而且每次读取的结果需要一样,即 a 时刻保持1;
- 事务 B 在事务 A 的处理过程中,修改了 a 的值,a=2;
事务 A 对于数据 a,不能保证重复读取时的值保持一致,这就是不可重复读。
-
幻读(Phantom):
- 事务 A 读取满足条件的某些数据,返回了 5 条数据;
- 事务 B 插入了新的满足同样条件的数据;
- 事务 A 因为业务需要再次读取数据,此次返回了 6 条数据,多出的数据就好像是“幻影”(Phantom)一样;
可以看到,“幻读”和“不可重复读”有点类似,两者都是在事务 A 过程中需要读取多次数据,但是期间数据被另一个事务 B 篡改,导致多次读到的数据不一致。
不同点在于,“不可重复读”是数据“值”的不一致,而“幻读”是数据记录的“数量”的不一致。 -
丢失修改(Lost to modify):
- 事务 A 和 事务 B 都要修改数据 num=2;
- 事务 A 和 事务 B 同时读到 num=2;
- 事务 A 把数据 num 减一变成 num=1;
- 事务 B 也把数据 num 减一,但确是在读到的初始值上减一(num=2-1=1),而不是在事务 A 的基础上减一(num=1-1=0)。
这样,事务 A 的操作结果被事务 B 的操作结果覆盖了,相当于事务 A 对数据的修改“丢失”了。
-
事务隔离级别
事务的隔离级别,就是能够避免在事务并发条件下产生的“不良反应”的能力,就是事务能隔绝其它事务的影响的能力。
事务的隔离级别越高,规避风险的能力也越强,事务在并发环境下出现的“不良反应”的概率越低。
“隔离级别越低,事务请求的锁越少或保持锁的时间就越短。”——《xx内幕InnoDB引擎》
“事务的隔离级别”,表示的是一种规范、约束,不同的数据库的具体实现都不一致,不同数据库采取不同的措施来保证事务达到对应的隔离级别。
MySql中包含四级的事务隔离级别,如下:
读未提交
READ-UNCOMMITTED,简写“RU”。应该扩展为“read uncommitted record”,即“可读未提交的记录”。表示在一个事务未提交时,另一个事物被允许读取相关的数据。
这是最低的隔离级别,相当于啥也没干,自然地,上述的“不良反应”在这种情况下都会发生。
读已提交
READ-COMMITTED,“read committed record”,“只能读已提交的记录”,简写“RC”。在一个事务提交后,另一个才被允许读取相关数据。
在这种级别下,当一个事务修改了数据,产生了“脏数据”,而该事务又尚未提交时,另一个事务不被允许去读取相关的数据,自然地这就解决了“脏读的问题”。
读已提交只允许读已提交的数据,避免了脏读现象。但是存在以下情况:在事务T1内,读取了数据D值为D1,然后T1执行其他SQL,事务T2更新了D为D2并提交,此时T1再次读取D时值为D2。这种情况称为不可重复读。
可重复读
REPEATABLE-READ,简写“RR”。这种隔离级别下,需要保证一个事务内多次读取某个记录,其数据都是一致的。该级别杜绝了“脏读”和“不可重复读”的问题。
可重复读只允许读已提交数据,而且在一个事务两次读取一个数据项期间,其他事务不得更新该数据,避免了不可重复读现象。虽然其他事务不得更新该数据,但是并未禁止不得插入新数据,这使得在一个事务内,两次同样的SELECT语句读取的记录数量是不一致的,这种情况称为幻读。
序列化
SERIALIZABLE,在这种隔离级别下,事务串行执行,能够解决“脏读”、“不可重复读”、“幻读”、“丢失修改”的问题,当然,因为是串行执行,所以它的性能是最低的。
MySQL中这四种隔离级别的字符、数字编号表示如下:
四种隔离级别说明
隔离级别 | 丢失更新 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|---|
未提交读(Read uncommitted) | 不可能 | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 不可能 | 可能 |
可串行化(SERIALIZABLE) | 不可能 | 不可能 | 不可能 | 不可能 |
脏读 :一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中,多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, “可重复读”在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据。
幻读 :一个事务读到另一个事务已提交的insert数据
本文来自博客园,作者:飞龙在生,转载请注明原文链接:https://www.cnblogs.com/flzs/p/13496321.html