文章目录
- 一、MySQL中各方面锁的分类
- 二、解释锁
- 2.1 全局锁
- 2.1.1 解释
- 2.1.2 全局锁的作用
- 2.1.3 释放锁
- 2.1.4 全局锁的场景(mysqldump)
- 2.1.5 全局锁加锁的方法
- 2.2 表级锁
- 2.2.1 表锁
- 2.2.1.1 解释
- 2.2.1.2 表锁的作用
- 2.2.1.3 释放锁
- 2.2.2 MDL(元数据锁)
- 2.2.2.1 解释
- 2.2.2.2 MDL的作用
- 2.2.2.3 MDL锁测试
- 2.2.2.4 解决MDL锁问题
- 2.3 行级锁
- 2.3.0 什么叫共享锁和排它锁?
- 2.3.1 解释
- 2.3.2 加锁方式
- 2.3.3 测试
- 2.3.3.1 共享锁
- 2.3.3.2 排它锁
- 2.4 行锁算法
- 2.4.1 间隙锁
- 2.4.1.1 解释
- 2.4.1.2 间隙锁的条件
- 2.4.1.3 测试
- 2.4.2 Recordlock锁
- 2.4.3 next-key锁
- 2.5 插入意向锁
粒度:全局锁、表锁、行锁、页锁(不做解释)
算法:记录锁(Record lock)、间隙锁(gap lock)、下一键锁(next-key lock)
实现机制:悲观锁、乐观锁
兼容性:共享锁(读锁)、排他锁(写锁)、意向锁。
2.1.1 解释
全局锁,字面意思就是MySQL全局的锁,MySQL使用Flush tables with read lock (FTWRL)来加全局读锁。
2.1.2 全局锁的作用
2.1.3 释放锁
2.1.4 全局锁的场景(mysqldump)
我们可以打开mysql的general_log。然后进行备份操作,general_log中会有加锁过程的。
general_log
2.1.5 全局锁加锁的方法
1.Flush tables with read lock
2.set global read_only=1
添加全局读锁的方法,目前仅支持以上两种,但是为什么我们不会用第二种呢?
原因:
1.read_only虽然的确可以起到MySQL全局只读的效果,但是在一个高可用软件中,read_only是判断主从身份的一个重要手段,如果我们将主库的该参数进行修改,那对主从架构将会有很大的影响。
2.在异常处理机制上有差异。如果执行FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。
3.read_only不能限制拥有super权限的用户,也就是说,如果这个用户拥有super权限,就算你打开该参数,该用户也能进行写操作。虽然mysql已经引进另外一个参数super_read_only,但是我们还是不建议使用。
MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。
2.2.1 表锁
2.2.1.1 解释
表锁,顾名思义就是限制单表的一种锁,可以通过语句(lock tables 表名 read/write)来限制该表。下面用小测试来讲述。
lock tables sbtest1 read
#当前会话:
当前会话对sbtest1无写权限,当前会话对别的表无修改及查看权限
#其他会话:
对所有表都有查询权限,对sbtest1表无修改权限
lock tables sbtest1 write
#当前会话
对sbtest1拥有查询权限和修改权限,对其他表没有修改权限和查询权限
#其他会话
对sbtest1没有查询权限和修改权限,对其他表有查询权限和修改权限
总结:
1.当对sbtest1表加上表锁的时候(不管read还是write),该会话对其他的表就没有了任何权限。
2.当对sbtest1加上read的表锁的时候,当前会话对sbtest1就只有读的权限,当对sbtest1加上write的表锁的时候,当前会话对sbtest1既有读的权限也有写的权限。
3.当对sbtest1加上read的表锁的时候,其他会话对sbtest1就只有读的权限,当对sbtest1加上write的表锁的时候,其他会话对sbtest1没有任何权限。
2.2.1.2 表锁的作用
在没有出现粒度更小的行锁的情况下,表锁是控制并发主要的方法。但是现在基本上没有人会锁定整个表,因为这样的对业务影响太巨大。
2.2.1.3 释放锁
2.2.2 MDL(元数据锁)
MDL全称metadata lock,所以又称元数据锁。
2.2.2.1 解释
MDL是另外一种表级别的锁,它不需要显示使用,也就是说,当你对一个表进行查询的时候,它会自动获得MDL读锁,当你对一个表进行增删改查的时候(比如修改表结构),会获得MDL写锁。
2.2.2.2 MDL的作用
MDL的作用是,保证读写的正确性。比如当你在进行查询的时候,另外一个人将你的表结构改了,想想就心头一颤。。
2.2.2.3 MDL锁测试
1.会话1(查询)
2.会话2(查询)
3.会话3(修改表结构)


总结:我们可以看到当有两个线程相继拿到MDL读锁的时候,再进行修改表结构等操作的时候,该线程会去拿该表的MDL写锁,但是读锁没有释放,写锁是拿不到的,所以该操作就会夯住,此刻该表就完全锁住了,后面的查询操作或者写操作也会被夯住,而且表锁不像行锁,不会有超时时间,会一直夯下去,直到你COMMIT或ROLLBACK。所以是比较危险的。
2.2.2.4 解决MDL锁问题
解决这个问题,也就是提交或者回滚这个事务,我们可以通过information_schema.innodb_trx这个表找到该事务。
2.3.0 什么叫共享锁和排它锁?
2.3.1 解释
2.3.2 加锁方式
2.3.3 测试
2.3.3.1 共享锁
总结:当一个线程获得一部分结果集(某些行)的共享锁的时候,其他线程可以获得该结果集的共享锁(可查询),但是不能获得该结果集的排它锁(不可修改)
2.3.3.2 排它锁
总结:当一个线程获得某部分结果集的排它锁的时候,其他线程不能获得该部分结果集的共享锁和排它锁。
PS : Next-KeyLocks=Gap锁+ Recordlock锁
2.4.1 间隙锁
(不锁记录,仅仅记录前面的Gap)
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件 的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”, InnoDB也会对这个“间隙”加锁。
2.4.1.1 解释
2.4.1.2 间隙锁的条件
gap lock的前置条件:
1 事务隔离级别为REPEATABLE-READ, innodb_locks_unsafe_for_binlog参数为0,且sql走的索引为非唯一索引(无论是等值检索还是范围检索)
2 事务隔离级别为REPEATABLE-READ, innodb_locks_unsafe_for_binlog参数为0,且sql是一个范围的当前读操作,这时即使不是非唯一索引也会加gap lock
2.4.1.3 测试
2.4.2 Recordlock锁
(锁数据,不锁Gap)
记录锁是对索引记录的锁。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;阻止任何其他事务插入、更新或删除 t.c1 值为 10 的行。 记录锁总是锁定索引记录,即使一个表没有定义索引。对于这种情况,InnoDB 会创建一个隐藏的聚集索引并使用该索引进行记录锁定。
2.4.3 next-key锁
插入意向锁是在插入一条记录行前,由 INSERT 操作产生的一种间隙锁。该锁用以表示插入意向,当多个事务在同一区间(gap)插入位置不同的多条数据时,事务之间不需要互相等待。假设存在两条值分别为 4 和 7 的记录,两个不同的事务分别试图插入值为 5 和 6 的两条记录,每个事务在获取插入行上独占的(排他)锁前,都会获取(4,7)之间的间隙锁,但是因为数据行之间并不冲突,所以两个事务之间并不会产生冲突(阻塞等待)。
总结来说,插入意向锁的特性可以分成两部分:
1.插入意向锁是一种特殊的间隙锁 —— 间隙锁可以锁定开区间内的部分记录。
2.插入意向锁之间互不排斥,所以即使多个事务在同一区间插入多条记录,只要记录本身(主键、唯一索引)不冲突,那么事务之间就不会出现冲突等待。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/178718.html