Mysql事务隔离级别与MVCC的实现

事务是一组原子性的查询单元,这组查询单元执行要么全部成功,要么全部失败。如果其中有任何一条语句因为崩溃或者其他原因导致失败,那么事务中的其他查询也会随之失败。

ACID特性

MySQL中事务必须满足ACID特性:
ACID表示:原子性(atomicity),一致性(consistency),隔离性(isolation)和持久性(durability)
原子性:一个事务必须是一个不可分割的原子单元,其内部执行逻辑要么全部成功要么全部失败。
一致性:事务的操作前后,数据库必须是从一个一致性状态到另一个一致性状态。
隔离性:一个事务内部的操作在最终提交前对于其他事务是不可见的。
持久性:事务一旦提交,其所做的修改必然会永久保存在数据库中,即使系统崩溃,修改的数据也不会丢失。

事务的隔离级别

隔离级别 指的是 事务与事务之间的关系

在sql标准中定义了4中隔离级别,每种隔离级别都规定了一个事务中所做的修改,事务与事务之间的可见性等等,都可以通过隔离级别控制。

隔离级别:

READ UNCOMMITTED(未提交读):
事务中的修改,即使没有提交,对于其他事务而言也是可见的。
事务可以读取到未提交的数据(脏读)
READ COMMITTED(已提交读):
某一事务的修改只有提交后才能被其他事务可见,这个级别可以有效的避免脏读,但无法避免不可重复读。
举个栗子说明:
事务A执行以下语句:

select * from table where class="三年级一班";  # 语句00
select * from table where class="三年级一班";  # 语句01

事务B执行以下语句:

update table set class='三年级一班' where name='小明';

那么假如事务A先执行完语句00时,事务B完成并提交,当事务A再次查询语句01时,会多出一条name='小明’的数据,这就叫做不可重复读。

REPEATABLE READ(可重复读):
可重复读解决了脏读的问题,也保证同一事务在多次读取同样记录的时候得到的数据是一样的,但无法避免幻读。
所谓幻读,指当事务读取某一范围的数据时,另一个事务又在该范围内插入了一条新的语句,当前面的事务再次读取该范围数据时,会产生幻行。
举个栗子:
事务A:

select * from table where class="三年级一班";  # 语句00
select * from table where class="三年级一班";  # 语句01

事务B:

insert into table table('三年级一班','小明');

当事务A执行完语句00的时候,事务B执行完成并提交,事务A再次执行语句01的时候,同样会多出一条记录‘小明’
注意:此时事务B执行的是插入语句

SERIALIZABLE(可串行化):
通过强制事务串行化执行,解决上面一切问题,就是慢。

多版本并发控制(MVCC)

MySQL大部分的事务型存储引擎都不是简单的行级锁,基于提升性能的角度考虑,一般都会实现多版本并发控制(mvcc)。
mvcc的实现,是根据数据在某个时间点的快照来实现的,也就是说,一个事务,不管执行多长时间,该事务从头到尾看到的数据都是一致的。根据事务的开始时间不同,每个事务在同一时刻看到的数据可能是不一致的。
InnoDB的MVCC,是通过在每行后面加两个隐藏列来实现的(分别保存行的创建时间和过期时间),当然里面存的并不是真正意义的时间,而是系统版本号。每开始一个新的事务,系统版本号都会递增,事务开始时间的版本号会作为当前事务的版本号。

对于不同操作,MVCC是如何工作的:

SELECT
InnoDB只会找
1、行版本号早于或等于当前事务版本号的数据,这样可以保证查的数据要么是事务开始前存在的,要么是该事务更新的。
2、并且行的删除标识,要么未定义,要么晚于当前事务版本号的数据
1,2条件为&关系
UPDATE
InnoDB为插入一行新纪录,保存当前事务版本号作为插入行的行版本号,同时保存当前事务版本号作为之前行的删除标识
DELETE
InnoDB为将当前事务版本号作为删除行的删除标识
INSERT
InnoDB为将当前事务版本号作为插入行的行版本号。

你可能感兴趣的:(Mysql)