MySQL 中事务的隔离级别一共分为四种,分别如下:
- 序列化(SERIALIZABLE)
- 可重复读(REPEATABLE READ)
数据库默认隔离级别 - 提交读(READ COMMITTED)
- 未提交读(READ UNCOMMITTED)
脏读 一个事务读到另外一个事务还没有提交的数据,称之为脏读
不可重复读 是指一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读
幻读 指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行
快照读
快照读(SnapShot Read)是一种一致性不加锁的读,是 InnoDB 存储引擎并发如此之高的核心原因之一。
在可重复读的隔离级别下,事务启动的时候,就会针对当前库拍一个照片(快照),快照读读取到的数据要么就是拍照时的数据,要么就是当前事务自身插入/修改过的数据。
当前读
与快照读相对应的就是当前读,当前读就是读取最新数据,而不是历史版本的数据,换言之,在可重复读隔离级别下,如果使用了当前读,也可以读到别的事务已提交的数据。
数据库行中多余的字段
-
DB_ROW_ID:该列占用 6 个字节,是一个行 ID,用来唯一标识一行数据。如果用户在创建表的时候没有设置主键,那么系统会根据该列建立主键索引。 -
DB_TRX_ID:该列占用 6 个字节,是一个事务 ID。在 InnoDB 存储引擎中,当我们要开启一个事务的时候,会向 InnoDB 的事务系统申请一个事务 id,这个事务 id 是一个严格递增且唯一的数字,当前数据行是被哪个事务修改的,就会把对应的事务 id 记录在当前行中。 -
DB_ROLL_PTR:该列占用 7 个字节,是一个回滚指针,这个回滚指针指向一条 undo log 日志的地址,通过这个 undo log 日志可以让这条记录恢复到前一个版本。
当我们开启一个事务的时候,首先会向 InnoDB 的事务系统申请一个事务 id,这个 id 是一个严格递增的数字,在当前事务开启的一瞬间系统会创建一个数组,数组中保存了目前所有的活跃事务 id,所谓的活跃事务就是指已开启但是还没有提交的事务。
当当前事务想要去查看某一行数据的时候,会先去查看该行数据的 DB_TRX_ID:
- 如果这个值等于当前事务 id,说明这就是当前事务修改的,那么数据可见。
- 如果这个值小于数组中的最小值,说明当我们开启当前事务的时候,这行数据修改所涉及到的事务已经提交了,当前数据行是可见的。
- 如果这个值大于数组中的最大值,说明这行数据是我们在开启事务之后,还没有提交的时候,有另外一个会话也开启了事务,并且修改了这行数据,那么此时这行数据就是不可见的。
- 如果这个值的大小介于数组中最大值最小值之间(闭区间),且该值不在数组中,说明这也是一个已经提交的事务修改的数据,这是可见的。
- 如果这个值的大小介于数组中最大值最小值之间(闭区间),且该值在数组中(不等于当前事务 id),说明这是一个未提交的事务修改的数据,不可见。