002MySQL学习014锁机制和MVCC机制

1 锁机制

1.1 概述

MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则。

不同的存储引擎支持不同的锁机制,InnoDB支持行锁和表锁,MyISAM支持表锁。

1.2 锁分类

1.2.1 共享锁和排他锁

按锁的互斥程度来分,可以分为共享锁和排他锁:

共享锁:多个读操作可以同时进行,其他写操作会被阻断。

排他锁:其他读操作和写操作均会被阻断。

1.2.2 表锁和行锁

按锁的粒度来分,可以分为表锁和行锁:

表锁:粒度最大的锁,表示当前操作对整张表加锁,资源开销小,不会出现死锁,锁冲突概率大。InnoDB和MyISAM都支持。

行锁:粒度最小的锁,表示当前操作对操作的行加锁,资源开销大,会出现死锁,锁冲突概率小。只有InnoDB支持。

2 锁细说

2.1 共享锁和排他锁

2.1.1 共享锁

共享锁(Share Locks),记为S锁,表锁,InnoDB和MyISAM都有。

读取数据时如果表上没有锁,则在表上加读锁,否则进入读锁队列。

2.1.2 排他锁

排他锁(Exclusive Locks),记为X锁,表锁,InnoDB和MyISAM都有。

更新数据时如果表上没有锁,则在表上加写锁,否则进入写锁队列。

2.1.3 优先级

当锁被释放时,优先执行写锁队列中的请求,写锁队列为空时,执行读锁队列中的请求。所以,如果有大量更新操作,可能会导致查询操作很难获得锁,从而长久阻塞,使程序响应超时。

2.1.4 加锁

对于更新语句,MySQL会自动加X锁,对于查询语句,MySQL不会自动加S锁。

当前线程给当前表加S锁,当前线程只能读取当前表,当前线程更新当前表失败,当前线程查询其他表失败,其他线程只能读取当前表,其他线程更新当前表阻塞。

当前线程给当前表加X锁,当前线程可以读取和更新当前表,当前线程查询其他表失败,其他线程读取当前表阻塞。

查看表上的锁:

show open tables;

在执行查询语句时,会自动给表加读锁,也可以显示加锁:

lock tables 表名 read;

在执行更新语句是,会自动给表加写锁,也可以显示加锁:

lock tables 表名 write;

释放锁:

unlock tables;

2.2 意向锁

2.2.1 说明

InnoDB为了支持多粒度锁机制,即为了支持表锁和行锁共存,引入了意向锁(Intention Locks)。

意向锁指的是在未来某个时刻,事务可能要加锁,先提前声明一个意向。

意向锁产生的目的主要是为了处理行锁和表锁之间的冲突,事务在请求S锁和X锁之前,需要先获得对应的IS锁和IX锁,在加S锁和X锁之前,会先加IS和IX锁。

使用意向锁提高了在多粒度锁并存时判断某行数据是否存在行锁的性能:

在没有使用意向锁的情况下,使用S锁或者X锁对某行加锁,其他线程在使用S锁或者X锁加表锁时,需要判断每行数据是否有锁。

在使用意向锁的情况下,使用S锁或者X锁对某行加锁,先使用对应的IS锁或者IX锁加表锁,其他线程在使用S锁或者X锁加表锁时,通过判断IS锁和IX锁即可,不需要判断每行数据。

2.2.2 意向共享锁

意向共享锁(Intention Share Locks),记为IS锁,表锁,MyISAM没有。

表示事务有意向对表中的某行加共享S锁。

2.2.3 意向排他锁

意向排他锁(Intention Exclusive Lock),记为IX锁,表锁,MyISAM没有。

表示事务有意向对表中的某行加排他X锁。

2.2.4 加锁

当前线程加IS锁并且给当前行加行锁,其他线程可以加IS锁并且给当前行加行锁,其他线程可以加IX锁并且给其他行加行锁,其他线程可以加S锁,其他线程不能加X锁。

当前线程加IX锁并且给当前行加行锁,其他线程可以加IS锁并且给当前行加行锁,其他线程可以加IX锁并且给其他行加行锁,其他线程不能加S锁,其他线程不能加X锁。

查询时加意向共享锁:

select * from 表名 lock in share mode;

查询时加意向排他锁:

select * from 表名 for update;

2.2.5 注意

使用意向锁必须开启事务,并且在begin之后,commit和rollback之前才会生效。

InnoDB行锁是针对索引加的意向锁,不是针对记录加的意向锁。

意向锁在某些情况下不会加行锁:

1)查询语句没有使用主键索引并且没有使用辅助索引,此时会使用表锁。

2)查询语句使用了范围条件导致索引无效,此时会使用表锁。

3)查询语句使用主键索引或者使用辅助索引,执行的结果没有数据,此时不会使用任何锁。

2.3 记录锁

记录锁(Record Locks),行锁,索引记录锁,建立在索引记录上的锁,为某行记录加锁,索引基于唯一索引(包括主键索引)。

查询时加共享记录锁:

select * from 表名 where id = 1 lock in share mode;

查询时加排他记录锁:

select * from 表名 where id = 1 for update;

2.4 间隙锁

间隙锁(Gap Locks),行锁,索引区间锁,建立在索引区间上的锁,为某个开区间加锁,开区间不包括端点。

使用间隙锁可以防止幻读,保证索引区间上的数据不会被更改。

需要注意的是,如果把MySQL的事务隔离级别降级为读已提交(Read Committed,RC),间隙锁就会自动失效。

查询时加共享间隙锁:

select * from 表名 where id > 1 lock in share mode;

查询时加排他间隙锁:

select * from 表名 where id > 1 for update;

2.5 临键锁

临键锁(Next-key Locks),行锁,记录锁和间隙锁的组合,索引区间是一个开区间,索引基于非唯一索引。

每个数据行都可以看做一个记录锁,数据行上下相邻两边的间隙可以看做两个间隙锁。

使用临建锁也可以防止幻读,保证索引区间上的数据不会被更改。

需要注意的是,如果把MySQL的事务隔离级别降级为读已提交(Read Committed,RC),临键锁就会自动失效。

临键锁在使用唯一索引的不同场景中会变化:

1)使用唯一索引,使用精确匹配,记录存在,变化为记录锁。

2)使用唯一索引,使用精确匹配,记录不存在,变化为间隙锁。

3)使用唯一索引,使用范围匹配,变化为临键锁,左开右闭。

4)使用无索引,变化为表锁。

2.6 插入意向锁

插入意向锁(Insert Intention Locks),行锁,特殊的间隙锁,多事务在同一个索引列上的同一个间隙中插入不同行的记录不会产生冲突。

多个事务同时在同一个间隙中插入记录时,获取各自的插入意向锁,获取在插入行上的排他锁,不同行的插入不会冲突。

2.7 自增锁

自增锁(Auto-inc Locks),表锁,特殊的表锁,发生在AUTO_INCREMENT主键自增的列,多事务同时插入时会阻塞,保证主键的连续。

3 MVCC机制

3.1 是什么

MVCC(Multi-Version Concurrency Control),多版本并发控制,是保证事务隔离性的机制。

最早的数据库系统只有读读支持并发,读写、写读、写写都会被阻塞,在引入MVCC机制后,只有写写会被阻塞,读读、读写、写读都支持并发。

不同的数据库引擎对MVCC机制有不同的实现,本文只学习MySQL数据库InnoDB引擎对MVCC机制的实现。

在RC读已提交中,MVCC机制解决了写读的并发问题,即解决了脏读的问题。在RR可重复读中,MVCC机制解决了读写的并发问题,即解决了不可重复读的问题。

注意,MVCC机制不能解决更新丢失的问题,但锁机制解决了这个问题,锁机制通过加锁保证写写不会并发。

4 MVCC原理

4.1 概述

在InnoDB引擎中,MVCC机制的实现主要靠表中的三个隐藏字段,undo日志,read视图实现的。

当前事务在执行查询语句时,会生成read视图,根据read视图判断查询当前表还是查询undo日志,不同的事务生成不同的read视图,可能查询当前表也可能查询undo日志。

把通过undo日志进行的查询操作称为快照读,无锁的查询操作有可能会执行快照读。把通过当前表进行的查询操作称为当前读,有锁的操作都会执行当前读。

4.2 概念

4.2.1 隐藏字段

在创建表时,除了创建定义的字段,还会默认创建三个隐藏字段:

trx_id:事务ID,记录最近修改和插入这条记录的事务ID。

roll_pointer:回滚指针,记录最近修改这条记录的上一版本,通过这个字段可以在undo日志中找到最近的历史版本。

row_id:隐藏主键,如果数据表没有主键,InnoDB会在这个字段创建聚簇索引。

其实还有删除标志字段,表示有事务将该记录删除了,事务提交前只是修改这个字段,事务提交后才会删除记录。

4.2.2 undo日志

undo日志可以看做一个版本链,用于保存修改和插入的历史版本,节点可以看做表中记录的拷贝,通过roll_pointer字段行成链式结构。

在执行快照读时,会根据roll_pointer遍历链表,直到找到符合要求的历史版本。

4.2.3 read视图

read视图可以看做一个事务快照,由当前系统中活跃的事务ID组成一个快照列表。

因为事务ID是按先后顺序生成的,所以需要比较要查询的记录的trx_id字段上的事务ID和read视图中的事务ID即可判断数据的来源:

1)如果trx_id小于read视图的最小值,说明最近更新这条记录的事务发生在过去已提交,执行当前读。

2)如果trx_id在read视图范围中,需要进一步判断。如果在read视图中能找到trx_id则表示事务未提交,执行快照读,如果找不到则表示事务已提交,执行当前读。

3)如果trx_id大于read视图的最小值,说明最近更新这条记录的事务发生在未来未提交,执行快照读。

4.3 结合操作举例说明

4.3.1 查询操作

执行查询操作时,生成read视图,对比数据行上的trx_id字段,进行当前读或者快照读。

在快照读时,如果找到的历史版本的删除标志字段不为空并且删除事务已提交,说明记录已被删除,不需要返回数据。

对于RC读已提交,同一个事务中的每次查询都会创建read视图,解决更新时读取产生的脏读的问题,不能解决读取时更新产生的不可重复读的问题。

对于RR可重复读,同一个事务中只有第一次查询会创建read视图,以后的查询都会使用已有的read视图,解决读取时更新产生的不可重复读的问题。

4.3.2 插入操作

复制新纪录到undo日志,当事务提交时删除此条undo日志,当事务回滚时反向操作然后删除和事务有关的undo日志。

插入记录,trx_id字段保存当前事务ID,roll_pointer字段为空。

4.3.3 修改操作

复制原记录到undo日志。

修改记录,trx_id字段保存当前事务ID,roll_pointer字段保存undo日志。

4.3.4 删除操作

复制原记录到undo日志。

修改记录,trx_id字段保存当前事务ID,roll_pointer字段保存undo日志,删除标志设为true。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mysql锁机制是用来处理并发访问数据库时的问题,特别是在使用InnoDB引擎支持事务的情况下。锁机制可以按照锁的粒度分为表级锁和行级锁。表级锁是对整张表进行加锁,实现简单,消耗的资源较少,加锁快速,不容易出现死锁。而行级锁则是对当前操作的行进行加锁,锁定粒度更小,可以提高并发性,但加锁的代价较高。 MySQL的InnoDB存储引擎默认的事务隔离级别是RR(可重复读),这是通过行级锁和多版本并发控制(MVCC)一起实现的。在正常读取数据时,不会加锁,而在写入数据时才会进行加锁操作。 MVCC是通过一些技术实现的,包括隐藏字段、Read View和Undo log。隐藏字段用于存储数据版本信息,Read View用于控制事务的隔离级别,而Undo log则用于记录事务对数据的修改操作,以便在需要回滚时进行恢复。 总结起来,Mysql锁机制包括表级锁和行级锁,用于处理并发访问数据库时的问题。而MVCC则是InnoDB存储引擎实现事务隔离级别的一种机制,通过隐藏字段、Read View和Undo log来实现数据的一致性和并发控制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mysql锁机制+MVCC](https://blog.csdn.net/qq_45901741/article/details/120245265)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MySQL之锁和事务](https://download.csdn.net/download/weixin_38739919/13683140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [mysql锁机制mvcc](https://blog.csdn.net/u014618114/article/details/115534734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值