MYSQL事务之ACID、隔离级别、MVCC、当前读和快照读

131 阅读4分钟

ACID

MYSQL事务满足ACID四个特性,即原子性一致性隔离性持久性

A,atomicity,原子性

原子性:事务中的所有操作构成一个不可分割的整体,要么全部提交成功,要么全部失败回滚

C,consistency,一致性

一致性:数据库的状态只能从一个一致性状态转换到另一个一致性状态

I,isolation,隔离性

隔离性:一个事务中所做的修改在最终提交之前对其他的事务不可见

D,durability,持久性

持久性:事务一旦提交成功,其所做的修改将永久保存,即使系统崩溃也不会丢失,直至被新的修改覆盖

隔离级别

SQL标准定义了四种隔离级别,即读未提交读已提交可重复读串行化。可重复读是MYSQL的默认隔离级别。

读未提交

读未提交:一个事务中执行查询操作能读取到其他事务中未提交的修改。

这种情况下可能造成脏读,因为未提交的修改有可能后续提交失败,触发回滚,那么这些修改不是有效的,是脏数据。

读已提交

读已提交:一个事务中执行查询操作只能读取到其他事务中已经提交的修改。

这种情况下不会再出现脏读,但可能出现不可重复读,在事务过程中对同一个数据进行了几次查询,而在查询间隙其他事事务成功提交了对该数据的修改,则可能导致这几次查询中返回的结果不一致的情况。

可重复读(默认级别)

可重复读:数据库保证每次一个事务中多次查询同一个数据返回的结果相同。 这种情况下不会出现不可重复读,但仍可能出现幻读,即在事务执行过程中,多次执行相同的范围查询,在查询间隙其他事务成功插入了新的记录,可能导致之后的查询结果出现多出来的“幻行”。

串行化

串行化:对每一行数据都加锁,强制事务只能串行执行,不会出现幻读,性能会比较差,且容易出现锁超时、争用问题。

多版本并发控制(MVCC)

隔离级别越高,数据一致性越好,但是也会对性能造成影响。

MYSQL默认隔离级别是可重复读,通过可重复读和MVCC一起解决幻读的问题。

MVCC

InnoDB维护了一个系统版本号,每开启一个事务,系统版本号就会自增,因此系统版本号可以作为一个事务的标识。

InnoDB的MVCC是通过在每行记录后保存两个隐藏列来实现的,一个列保存的是插入该记录的事务的系统版本号,另一个列保存了删除该记录的事务的版本号。

SELECT

只返回插入版本号小于等于当前事务的系统版本号,且删除版本号未定义或者大于当前事务系统版本号的行。

INSERT

InnoDB为每个新增行保存当前系统版本号作为插入版本号

DELETE

InnoDB为每个删除行保存当前系统版本号作为删除版本号

UPDATE

InnoDB将修改后的结果作为新记录插入,将当前系统版本号作为新记录的插入版本号,并将对应的旧记录标记为删除,即将当前系统版本号作为旧记录的删除版本号

由于系统版本号的唯一和递增属性,在上述条件限定下,一个事务中执行多次相同查询将返回相同的结果,不会出现不可重复读和幻读。

在InnoDB中,MVCC只在读已提交和可重复读两个隔离级别下工作。

当前读和快照读

当前读(current read)

显式或隐式的加锁读,读取的是记录的最新版本,并且当前读返回的记录都会加上锁,保证其他事务不会再并发修改这条记录

快照读(snapshot read)

  1. 一致非锁定读,就是普通SELECT语句,不加锁
  2. 快照读SELECT 的时候,会生成一个版本快照
  3. READ COMMITTED (读已提交)隔离级别下,每次读取都会重新生成一个快照;REPEATED READ (可重复读)隔离级别下,快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照