MySQL 锁学习笔记
1.Mysql中有哪几种锁?
按作用范围划分:
1.全局锁:作用在整个数据库实例上的锁;
2.表锁:作用在表上的锁,主要有意向锁,表共享锁,表排他锁以及自增锁;
3.行锁:作用在行上的锁,MyISAM 不支持,InnoDB 支持,主要分为记录锁,间隙锁,临键锁;
按兼容性划分:
1.共享锁(S锁,读锁):只允许其他事务都上共享锁,只能读取数据,不能改写数据;
2.排他锁(X锁,写锁):不允许其他事务上任何锁,只能获取锁的事务读取和改写数据;
特殊锁:
1.自增锁:只用于自增列的锁,属于表锁,瞬发锁,只占用一小段时间,是为了保证自增的插入顺序。
2.全局锁,表级锁和行级锁了解吗?有什么区别?
首先就是作用范围不用,顾名思义;
再者就是不同的引擎所支持的锁级别不同,MyISAM 不支持 行锁,InnoDB 支持 行锁;
接着就是包含的锁不同,表锁有意向锁,表共享锁,表排他锁以及自增锁,而行锁有记录锁,间隙锁,临键锁,插入意向锁;
3.InnoDB 行锁的具体类型
InnoDB 包含的行锁主要有:
1.记录锁:只对具体的记录加锁;
2.间隙锁:对某一个范围加锁;
3.临键锁:则是记录锁和间隙锁的结合体;
4.意向插入锁:是一个特殊的间隙锁,只与间隙锁和临键锁阻塞,插入意向锁只与行级锁(间隙锁/临键锁)交互,与表级锁无直接关系。
4.意向锁有什么作用?插入意向锁和意向锁的区别?
意向锁主要是表级别的意向共享锁,意向排他锁以及行级别的意向插入锁;
1.表意向锁:
表级别的意向锁主要是为了平衡多粒度锁的性能,当有事务要对表里的行上锁,则先会获取表的意向锁,再上行锁,这样做的好处是当有另一个事务需要对表上锁时,并不需要遍历整个数据表判断是否有上行锁才能上表锁,而是直接通过表的意向锁判断是否可以上表锁,可以是何种表锁;
同一个表允许有多个事务获取意向共享锁和意向排他锁,有意向共享锁的表只能上表共享锁,有意向排他锁的表不能说任何表共享锁和排他锁。
2.意向插入锁:
意向插入锁只与间隙锁和临键锁阻塞。同一个范围的意向插入锁可以被多个事务获取,只要没有唯一值约束阻塞或者与间隙锁和临键锁阻塞,插入都可以执行成功,是为了解决重复读隔离级别下的幻读问题,意向插入锁和临键锁的联用才是解决在当前读环境下,重复读幻读问题的具体原理。
5.为什么会锁升级?锁升级的原理又是什么?
因为行锁粒度细所以内存,cpu 等资源开销大,所以当某个事务的行锁超过一定阈值时,行锁的收益小于表锁,所以需要升级锁,行锁升级到表锁后不会降级;
锁升级是为了降低系统因大量行锁而产生的内存和 CPU 开销。当一个事务持有的行锁超过 InnoDB 内部设定的阈值(大约 20,000 个),InnoDB 会尝试将这些行锁升级为表锁。升级过程会尝试获取表锁,成功后释放已有行锁,所有锁控制转由表锁进行。锁升级是单向的,一旦升级不会自动降级为行锁。
6.共享锁和排他锁的区别?
共享锁和排他锁即可以是表级别也可以是行级别;
共享锁下只允许读取数据,可以有多个事务同时获取,排他锁下允许读取和改写数据,但是当且仅当一个事务获取;
共享锁通过 LOCK ... READ 和 for share 指令上锁,排他锁通过 LOCK ... WRITE 和 for update 指令上锁;
7. 可重复读只有一次 Readview 怎么还会幻读呢?
可重复读隔离级别确实只创建一个 ReadView,因此对于快照读不会产生幻读。但在当前读(如 SELECT ... FOR UPDATE、UPDATE)中,InnoDB 是基于最新数据而不是快照进行访问,此时可能出现幻读。为了防止幻读,InnoDB 在 Repeatable Read 隔离级别下使用 Next-Key Lock(记录锁 + 间隙锁)锁定查询范围,从而避免其他事务插入幻行。
8.悲观锁与乐观锁区别是什么?
悲观锁:假设并发冲突一定会发生,先加锁再操作,mysql 内置锁都是悲观锁;
乐观锁:假设并发冲突很少发生,先操作再检查, 通常通过版本号、时间戳、CAS 等机制实现。
9.MySQL 实现不同隔离级别的原理,以及 MVCC 和锁的转换过程是什么?
不同隔离级别的实现原理:
1. Read Uncommitted(读未提交):不使用 MVCC,所有读操作不加锁也不判断版本,可以读到其他事务尚未提交的数据(脏读);
2. Read Committed(读已提交):使用 MVCC:每次 SELECT 都读取最新提交版本,每次读取时重新构造快照(Read View),可以防止脏读,但不可重复读;
3. Repeatable Read(可重复读,MySQL 默认):使用 MVCC,一个事务在开始时创建一次 Read View,整个事务周期内都用这个版本读,所以实现可重复读,同一行多次查询结果一致;幻读也可以通过(间隙锁/临键锁+意向插入锁)避免:修改/插入带条件的记录时加锁范围覆盖可能的“幻行”
4. Serializable(可串行化):所有读都加共享锁(S),所有写都加排他锁(X),强一致性但并发最低。
MySQL 的隔离级别通过 MVCC 和锁机制共同实现。对于读操作,InnoDB 主要依靠 MVCC 快照来提供一致性视图,实现不同隔离级别;对于写操作,使用行锁、间隙锁等方式来避免冲突。MVCC 通过隐藏列和 Undo Log 构建出数据的多个版本,快照读无需加锁即可保证事务一致性。而在显式加锁读或写操作中,InnoDB 会切换为锁机制,保证隔离性和一致性。
10. 死锁检测与处理流程
锁是指两个或多个事务在执行过程中,因竞争资源而互相等待,导致永远无法继续执行的现象。
InnoDB 通过构建等待图的方式进行死锁检测,当检测到死锁时,会自动回滚其中一个事务来解除死锁,优先选择开销最小的事务回滚。死锁检测是实时的,在事务加锁等待时触发,而不是依赖超时机制。
事务 A 请求锁 → 判断锁被事务 B 持有 → 标记为等待 → 构建等待图 → 检查是否成环。