事务
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行结果必须使数据库从一种一致性状态变到另一种一致性状态。事务时逻辑上的一组操作,要么都执行,要么都不执行。
事务四个特性
ACID
- 原子性(Atomicity)。事务是执行的最小单位,不允许分割。要么全部完成,要么全部不完成。
- 一致性(Consistency)。执行事务前后,数据库从一个一致性状态变到另一个一致性状态。
- 隔离性(Isolation)。并发访问数据库时,一个用户的事务不被其它事务干扰,各并发事务之间的数据库是独立的。
- 持久性(Durability)。一个事务提交后,对数据库的改变是持久的,即使数据库发生故障也不应该对其有影响。
A、I、D是手段,C是目的。
并发事务的问题
脏读
一个事务对数据进行了修改,这个修改对其它事务是可见的,即使当前事务没提交,其它事务能读取到这个修改了的数据,但是当前事务突然回滚,数据改回去了,其它事务读取到的就是脏数据。这就是脏读。
丢失修改
一个事务对数据进行了修改,另一个事务又对这个数据进行了修改,导致第一个修改结果丢失了。称为丢失修改。
不可重复读
指在一个事务内多次读同一数据。在多次读同一数据的期间,有其它事务修改了该数据,导致多次读到的数据不一致。所以叫不可重复读。
幻读
与不可重复读类似,只不过不可重复读是修改数据,幻读是插入数据。一个事务读取了几行数据,另一个事务此时插入了一些数据,随后的查询中第一个事务就会发现多了一些原本没有的数据,就行发生幻觉了一样,所以称为幻读。例如,一个事务执行select count(*) from user,之后另一个往user表中插入了几条数据,之后第一个事务再执行相同命令时会发现多了几条数据。
并发事务的控制方式
锁和MVCC。 锁悲观,MVCC乐观。
- MySQL中的锁为读写锁,分为读锁(共享锁)和写锁(排他锁 / 独占锁)。读锁允许多个事务同时获取,写锁只能一个事务获取。另外,根据锁粒度的不同,又分为表级锁和行级锁,InnoDB默认为行级锁。不管是表级锁还是行级锁,都存在读锁和写锁两种类型。
- MVCC是多版本并发控制方法,即对一份数据存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。
MySQL的事务隔离级别
事务隔离级别有四种:
- 读取未提交。 最低的隔离级别。允许读取尚未提交的数据变更,可能会导致脏读,幻读或不可重复读。
- 读取已提交。 允许读取已经提交的数据变更,可以防止脏读,但是仍可能发生幻读和不可重复读。
- 可重复读。 对同一字段读取到的数据是一致的,除非是被自身事务修改。可以防止脏读和不可重复读,但是仍可能发生幻读。
- 可串行化。 最高的隔离级别,所有事务依次逐个执行。可以防止脏读,不可重复读和幻读。
MySQL的默认隔离级别是可重复读。
MySQL怎么实现隔离级别的?
MySQL的隔离级别是基于锁和MVCC共同实现的。
可串行化隔离级别是通过锁来实现的。读已提交和可重复读隔离级别是基于MVCC实现的。
MVCC原理
对于InnoDB,聚簇索引记录中包含3个隐藏的列:
- ROW ID: 隐藏的自增ID,如果表没有主键,InnoDB会自动按ROW ID产生一个聚簇索引树。
- 事务ID:记录最后一次修改该记录的事务ID。
- 回滚指针:指向这条记录的上一个版本。
后续待更新