天天看点

mysql 你用的什么隔离级别?并发问题,腾讯面试官让我回家再看看

作者:梦幻随风的互联网笔记
mysql 你用的什么隔离级别?并发问题,腾讯面试官让我回家再看看

1.面试官考察重点会是?

mysql:存储引擎、索引,事务

InnoDB是默认的数据库存储引擎支持事务。默认的事务隔离级别是 可重复读,通过MVCC(并发版本控制)来实现。

2.什么是可重复读?

repeatable read(mysql的默认隔离级别) 一个事务第一次读过某条记录后,另一个事务修改提交了该条记录后,事务a读取到的还是第一次的值,这就是可重复读,同一个事务中多次读取相同的数据返回的结果是一样的。事务不会读到其他事务对已有数据的修改,即使其他事务已提交,也就是说,事务开始时读到的已有数据是什么,在事务提交前的任意时刻,这些数据的值都是一样的。

3.什么是幻读?脏读?

例如:

第一个事务查询一个User表id=100发现不存在该数据行,

这时第二个事务又进来了,新增了一条id=100的数据行并且提交了事务。

这时第一个事务新增一条id=100的数据行会报主键冲突, 第一个事务再select一下, 发现id=100数据行已经存在,

这就是幻读。

脏读 就是一个事务读到另一个事务没有提交的数据。事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,事务B读到的就是脏数据。

4.可重复读会引发幻读和脏读吗?

可重复度 对于其他事务新插入的数据是可以读到的,这引发了幻读问题。

其避免了脏读和不可重复读问题,但幻读依然存在。

还是会出现幻读,(但是mysql解决了幻读的问题),

通过 undolog版本链和 readview实现,其实就是 mvcc

InnoDB实现mvcc 是通过 readview+undolog 来实现

5.MVCC 多版本并发控制(Multi-Version Concurrency Control, MVCC)

不仅仅是解决数据库的并发问题,很多并发场景都可以使用,他介于使用乐观锁和悲观锁之间,是一个重要的并发设计方案。

仅在读提交和可重复读两种隔离级别下生效

每行记录字段都保存有:

一个最近变更事务Id row trx_id

一个最新删除的事务Id roll_pointer

mysql 你用的什么隔离级别?并发问题,腾讯面试官让我回家再看看

6。ReadView包含的内容

  • m_ids 。在生成ReadView时,当前系统中活跃的读写事务的事务id列表,即还未提交。
  • min_trx_id 。在生成ReadView时,当前系统中活跃的读写事务中最小的事务id;也就是m_ids中 的最小值。
  • max_trx_id 。在生成ReadView时,系统应该分配给下一个事务的事务id值。
  • creator_trx_id 。生成该ReadView的事务的事务id。

可重复读 读数据的原则 简单来说 就是:

读 版本号 小于等于 当前版本的数据( 意思就是读不到在当前事务之后修改的数据 避免了不可重复读)            

读 删除事务版本号 大于 当前版本的数据( 意思就是如果这条数据在之后的事务里删了,当前事务也能读)

可重复读,在第⼀次读取数据时⽣成⼀个ReadView,只会在第⼀次执⾏查询语句时⽣成⼀个 ReadView ,之后的查询就不会重复⽣成了,所以⼀个事务的查询结果每次都是⼀样的。

具体分析是:

如何通过ReadView来判断记录的某个版本是可见的?(小于、等于、不在、坚持回溯)

  • 如果trx_id == creator_trx_id,则表明当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  • 如果trx_id < min_trx_id,则表明生成该版本的事务在当前事务生成ReadView之前已经提交了,所以该版本可以被当前事务访问。
  • 如果trx_id >= max_trx_id,则表明生成该版本的事务在当前事务生成ReadView之后才开启,所以该版本不可以被当前事务访问。
  • 如果trx_id in m_ids,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问。
  • 如果trx_id not in m_ids,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
  • 如果某个版本的数据对当前事务不可见,那就顺着版本链找到下一个版本的数据,并继续执行上面的步骤来判断记录的可见性,以此类推,直到版本链中的最后一个版本。

在可重读Repeatable reads事务隔离级别下:

SELECT时,读取创建版本号<=当前事务版本号,删除版本号为空 或>当前事务版本号。

INSERT时,保存当前事务版本号为行的创建版本号

DELETE时,保存当前事务版本号为行的删除版本号

UPDATE时,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行

通过MVCC,虽然每行记录都要额外的存储空间来记录version,需要更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,大多读操作都不用加锁,读取数据操作简单,性能好。

7.innodb事务日志包括redo log和undo log。

redo log是重做日志,提供前滚操作。(redo log通常是物理日志,记录的是数据页的物理修改)

undo log是回滚日志,提供回滚操作。(undo用来回滚行记录到某个版本。 undo log一般是逻辑日志,根据每行记录进行记录。)

undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志。

8.版本链

在每次更新该记录后,都会将旧值放到一条undo日志中。随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一条链表,这个链表就称之为版本链。

undo log 的回滚机制也是依靠这个版本链,每次对记录进⾏改动,都会记录⼀条undo⽇志,每条undo⽇志也都有⼀个 roll_pointer 属性(INSERT操作对应的undo⽇志没有该属性,因为该记录并没有更早的版本),可以将这些undo⽇志都连起来,串成⼀个链表

mysql 你用的什么隔离级别?并发问题,腾讯面试官让我回家再看看

祝你早日进阶,加油!

mysql 你用的什么隔离级别?并发问题,腾讯面试官让我回家再看看

继续阅读