并发存在的问题#
- 脏读:一个事务「读到」了另一个「未提交事务修改过的数据」
- 不可重复度:在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了「不可重复读」现象。
- 幻读:在一个事务按照条件查询数据时,没有对应的数据行,但在插入数据后,这行数据又存在。
事务的隔离级别#
读未提交:脏读,不可重复读,幻读 读提交:不可重复读,幻读 可重复读:幻读 串行化:
- 当前读:读取的是最新版本
- 快照读:读取的是记录数据的可见版本
mvcc实现#
隐藏字段#

trx_id,当一个事务对某条聚簇索引记录进行改动时,就会把该事务的事务 id 记录在 trx_id 隐藏列里; roll_pointer,每次对某条聚簇索引记录进行改动时,都会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。
undolog#
undo log版本链
readView#


如果记录的 trx_id 值小于 Read View 中的
min_trx_id值,表示这个版本的记录是由"创建 Read View 之前就已经提交的事务"生成的,所以该版本对当前事务可见。如果记录的 trx_id 值大于等于 Read View 中的
max_trx_id值,表示这个版本的记录是由"创建 Read View 之后才启动的事务"生成的,所以该版本对当前事务不可见。如果记录的 trx_id 值介于
min_trx_id和max_trx_id之间(即min_trx_id <= trx_id < max_trx_id),说明该事务的 id 在 Read View 创建之前就已经分配出去了,此时需要进一步判断 trx_id 是否在m_ids列表中:- 如果 trx_id 在
m_ids列表中,表示生成该版本记录的事务在创建 Read View 的那一刻仍然活跃(尚未提交),所以该版本对当前事务不可见。 - 如果 trx_id 不在
m_ids列表中,表示该事务虽然 id 已分配,但在创建 Read View 时已经提交,所以该版本对当前事务可见。
- 如果 trx_id 在
「读提交」隔离级别是在每个 select 都会生成一个新的 Read View,也意味着,事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能这期间另外一个事务修改了该记录,并提交了事务。
「可重复读」隔离级别是启动事务时生成一个 Read View,然后整个事务期间都在用这个 Read View,这样就保证了在事务期间读到的数据都是事务启动前的记录。
Reply by Email