Mysql中的锁以及MVCC

Mysql中的锁以及MVCC

课程安排

  • MySQL中的锁应用
  • MySQL中的MVCC应用

MySQL中锁的应用?

  • 事务的隔离在底层是如何实现的?
1. 读写锁
2. 一致性快照读(MVCC-多版本并发控制)
  • mysql中的锁是如何分类的?
1. 从性能上讲可以分为乐观锁和悲观锁。
2. 从操作类型上讲可以读锁(共享锁)和写锁(排它锁)
3. 从数据操作粒度上来讲可以分为全局锁、表锁、行锁、间隙锁(between 100 and 200)、...
  • 如何理解MySQL中的MVCC(Multi version concurrent control)?
MVCC称之为多版本并发控制,它是通过读取历史版本的数据,来降低并发事务的冲突(尽量减少阻塞),
进而提高事务的并发效率。
  • 如何理解MySQL中的全局锁?
全局锁是要关闭所有打开的表。在MySQL可以使用全局读锁锁定所有表,通常应用于逻辑备份,我们在执行
数据库备份时,不允许其它事务对数据库进行更新了,因为这样可能会导致备份的数据与库中实际的数据
不一致。
  • MySQL中的全局锁是如何应用的?
1. 加全局读锁 (flush tables with read lock): 只能读库中所有表的数据,但是不能写(insert,update,delete)。
2. 解锁 unlock tables
  • 如何理解MySQL中的表级锁?
表锁一般是针对与某张表进行锁定,包括表锁(表读锁和表写锁)和元数据锁(Metadata Lock-MDL)。
  • 如何对MySQL中的表添加读锁(共享锁)、写锁(排它锁)?
1. 读锁(lock table regions read):所有线程可以读,当先线程写会出错,其它线程写会阻塞。
2. 写锁(lock table regions write):当前线程可以读写,其它线程读写要阻塞。
  • 如何理解MySQL中的行锁?
行锁就是针对表中的某一行进行锁定。
  • 如何对MySQL表中的行添加行锁(InnoDB默认select操作不加锁)
1. 共享锁 (select * from regions where id=13 lock in share mode),又称为S锁,
   允许当前事务读取一行,阻止其它事务获取相同数据集的排它锁。
   
2. 排它锁 (select * from regions where id=13 for update),又称为X锁。
   允许当前事务更新数据,阻止其它事务获取相同数据集的共享锁和排它锁。

MVCC(多版本并发控制)

  • MVCC 是什么?
MVCC(Multi Version Concurrent Control)多版本并发控制,它可以通过历史版本
保证读数据的一致性,但是这样方式相对于添加排它锁,并发性能要好.
  • 你是否还记得事务的四个特性,底层是如何保证这些特性成功的?
1. 原子性(通过undolog实现-执行回滚)
2. 隔离性(通过锁,MVCC-多版本并发控制)
3. 一致性(通过undolog,redolog,binlog)
4. 持久性(通过redolog日志实现)

  • MVCC的底层逻辑是如何实现的呢?
MVCC的实现原理主要依赖于记录中的undolog(回滚日志),ReadView(读视图-快照读),三个隐藏字段来实现的.
  • MVCC中的三个隐藏字段指的是哪些?(了解)
1. DB_TRX_ID:记录创建这条记录或者最后一次修改该记录的事务id
2. DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undolog实现数据的回滚.
3. DB_ROW_ID:隐藏的主键,如果数据表没有主键,也没有非空且唯一的字段,那么innodb会自动生成一个row_id。
  • 如何理解MVCC中的版本链?

当我们开启了一个事务,并且这个是要对数据进行更新,此时会产生一条undo日志,多个事务同时操作 这一条记录时候,那就会产生多个版本的undo日志,这些日志会通过回滚指针(DB_ROLL_PTR)构建一个 链表,这个链表就称之为版本链。

 

  • 如何理解快照读?

快照读也称之为普通读,读取的是记录中的可见版本数据,这种读加锁,就是普通的select。

  • 如何理解当前读?

当前读也称之为锁定读(Locking Read),读取的记录是数据的最新版本,这种读需要在读之前 先获取对应记录的锁。

select * from xxx where id=1 lock in share mode;
select * from xxx where id=1 for update;
  • 什么是ReadView?

ReadView提供了某一时刻事务系统的一个快照,主要用来做“可见性”判断。这个ReadView中也保存了 对本事务不可见的一些其它活跃事务的id。

  • ReadView应用场景?
对于Read Committed和Repeatable Read的隔离级别,都要读取已经提交的事务数据,也就
是说如果版本链中的事务没有提交,该版本的记录是不能被读取的,那哪个版本的事务是可以读取
的,此时就引入了ReadView. MySQL数据库隔离级别中的Read Committed和Repeatable Read
底层都是通过这个MVCC实现的。

  • ReadView中包含什么?

MySQL5.7版本中的ReadView中包含了如下几个属性:

1. m_ids: 截止到当前事务id之前,所有活跃的事务id(还没有commit的事务)。例如m_ids[1,2,3,4]
2. min_trx_id: 记录活跃事务id中(m_ids)的最小值。例如 1;
3. max_trx_id: 保存当前事务结束后应分配的下一个事务id值。例如 5;
4. creator_trx_id: 保存创建ReadView的当前事务id。例如 4;

 

ReadView 会根据图中的四个属性,再集合undo日志版本链,实现MVCC机制,决定一个事务可以读取到的数据版本。

  • ReadView 可见性判断的规则是怎样?
1. 如果db_trx_id与Readview中的creator_trx_id是否相等,则说明当前事务在访问自己的操作数据,此时可以访问。
2. 如果db_trx_id小于ReadView中的min_trx_id值,表明生成的该版本的事务在当前事务生成readview之前已经提交,所以可以直接读取.
3. 如果被访问版本的db_trx_id大于ReadView中的max_trx_id值,表明该版本的事务在当前事务生成ReadView后才开启的,所以该版本不可以被当前事务访问. 
4. 如果访问的版本的db_trx_id属性值在min_trx_id和max_trx_id之间,就需要判断一下db_trx_id的值是不是在m_ids列表中,如果在,说明创建ReadView时,生成的该版本的事务还是活跃的,该版本不可以访问,如果不存在,则说明创建ReadView时,生成该版本的事务已经提交则可以读取.

  • 事务隔离(RC-Read Committed,RR-Repeatable Read)何时创建ReadView视图?

1.Read Committed隔离级别每次select都会创建一个新的ReadView.(可以读取已提交的数据)

2.Repeatable Read隔离级别是第一次select时创建一个ReadView.(每次只能读取当前事务的数据)

  • 案例分析(读已提交这个隔离级别是如何通过MVCC去是实现)

例如:现有一个Regions的undo日志链,事务的版本号(DB_TRX_ID)为10,主键region_id值为1,region_name值为A

第一步:假设现在有两个并发事务,分别为事务A和事务B:

事务A(DB_TRX_ID=20): select * from regions where region_id=1;
事务B(DB_TRX_ID=30): update regions set region_name='AA' where region_id=1;

事务A的ReadView为:

m_ids=[20,30]
min_trx_id=20
max_trx_id=31
creator_trx_id=20

事务B的ReadView为:

m_ids=[20,30]
min_trx_id=20
max_trx_id=31
creator_trx_id=30

第二步:事务A开启后,通过版本链第一读取数据,版本链中的DB_TRX_ID为10,这个值小于事务A的 DB_TRX_ID=20的值,说明DB_TRX_ID=10这条记录是事务A开启之前就已经写的,并且提交了事务, 所以这条记录事务A是可以读取到的。

第三步:事务B(DB_TRX_ID=30)修改数据,将region_name修改为'AA',这个修改后也要写入undo日志,

第四步:事务A(DB_TRX_ID=20)再次读取region_id为1的记录,此时在undo版本链中,最新版本的 事务id值为30,这个值在事务A的ReadView中的m_ids数组中,表示这个事务是活跃事务,事务A是读取不到的。 此时事务A会沿着undo日志的版本链继续向前查找,这样就会找到DB_TRX_ID值为10的记录,这条记录的事务id 值小于事务A的ReadView中的min_trx_id值,这个事务应该为一个已提交的事务,所以事务A可以读取这条记录。 此时拿到的region_name的值为'A'

第五步:现在事务B提交,此时系统中的活跃事务就只有事务A了,事务A在第三次读取时,可以读取到的内容就 有两种可能了,假如事务的隔离级别为RC级别,读取到的数据就是'AA'。假如事务的隔离级别RR,此时读取到的 数据就是'A';

总结(Summary)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值