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