目录
锁的分类
全局锁内容
表级锁
行级锁
间隙锁/临键锁(也属于行锁)
锁的分类
全局锁:锁定数据库中所有表
表级锁:锁定该表全部内容
行级锁:只锁定该行数据
全局锁内容
全局锁就是将数据库中包含的所有的表都锁住,加锁之后整个的实例都处于只读状态,后面的所有的DML。DDL语句以及涉及更新事务的提交语句都会被阻塞
全局锁的核心运用场景是全局库的备份,对所有表进行锁定,防止出现不一致问题
例子如下:
首先没有添加全局锁,在备份tb_stock过程中产生业务扣减库存,但是tb_stock在备份过程中没有备份新数据
由于后面的表没有锁,所以其表内容新增了,后续在备份后面的表的时候,是还会备份新的业务数据的
也就是tb_stock没有备份到新的数据,tb_order以及tb_orderlog备份到了新的数据-->出现不一致问题
加锁后,DML语句,DDL语句被阻塞,DQL(查询语句正常)
加锁命令以及解锁命令
flush tables with read lock
unlock tables
使用全局锁产生的问题
1.如果是在主库上进行操作,备份的所有过程中是不能够进行数据的更新的,业务停摆
2.如果是在从库上进行备份,从库将很长一段时间不能从主库同步二进制日志,导致同步延迟--->主从不一致
使用不加锁的方式备份数据
mysqldump --single-transaction -uroot -p123456 itcast > itcast.sql
表级锁
意思就是每次操作锁住整张表
表级锁的分类
- 表锁
- 元数据锁
- 意向锁
表锁
表锁又分两类,读和写锁
读锁不会阻塞其他客户端的读但是阻塞写(表共享读锁),写锁即阻塞读也阻塞写(表独占写锁)
加锁语法
lock tables 表名... read/write
unlock tables
元数据锁
元数据锁不是用来手动加锁的,是系统自动控制的,在访问一张表的时候会自动加上。
MDL锁的主要作用就是维护表元数据的数据一致性,在表上有活动的事务的时候,不可以对元数据进行写入操作。未来避免DDL和DML冲突
当对一张表进行curd的时候,添加MDL读锁,当对表结构进行修改的时候,添加MDL写锁(排它)
查看元数据锁的命令
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks;
意向锁
背景:当在一张表中,如果有一行数据被行级锁锁住的时候,表锁是不能直接添加到该表上的,避免冲突。原始情况加表锁的时候,要一行一行检查有没有行锁,效率低下
意向锁目的就是加速检查速率,使用意向锁减少表锁的检查,在一个表中添加行锁的时候,会在该表上添加一个意向锁
分类
意向共享锁(IS):与表锁共享锁(read)兼容,与表锁独占锁不兼容(write)
select ... lock in share mode
意向独占锁(IX):与表锁共享锁以及独占锁都不兼容,需要注意意向锁之间都是兼容的
insert 、update 、delete 、select ... for update
通过命令查看意向锁以及行锁的情况
select object_schema,object_name,index_name,lock_type,lock_mod,lock_data from performance_schema.data locks;
行级锁
分类:
- 共享锁:允许一个事务去读一行,阻止其他事务获取相同数据集的排他锁
- 独占锁:允许获取排他锁的事务去更新数据,其他事务不能获取相同数据集的共享锁和独占锁
不同的sql语句对应的行锁的类型
默认情况下,InnoDB在可重复的事务隔离级别允许,InnoDB使用next_key(就是行锁+间隙锁)锁进行搜索和索引扫描避免幻读
- 对于唯一索引进行检索的时候,对于已经存在记录进行等值匹配时,会自动优化为行锁(因为是唯一索引,只可能存在一个该值的记录,不需要间隙锁来保证间隙中出现重复记录)
- InnoDB的行锁是针对索引加的锁,如果有不通过索引条件检索数据,那么此时InnoDB环境下会直接锁表,也就是表锁。意思就是在update .... where ....,如果where后面跟着的条件不是索引列,直接锁表
查看意向锁以及行锁的加锁情况
select object_schema,object_name,index_name,lock_type,lock_mod,lock_data from performance_schema.data_locks;
间隙锁/临键锁(也属于行锁)
首先了解InnoDB索引树的叶子节点的形式
间隙锁的意思就是在两个数据之间的间隙,例如上图有6和12两个数据,间隙锁就是加在6到12中间的这部分范围(注意是不包含6和12的)
临键锁的意思可以视作是行锁+间隙锁,锁的范围就是一行以及该行之前的所有记录范围,以上图为例,与6有关的间隙锁锁的范围就是6这一行的数据+6之前的范围
默认情况下,InnoDB在可重复读事务隔离级别运行,InnoDB使用next-key(临键锁)进行搜索和索引扫描,以防止幻读。
幻读问题就是对于一个范围内的数据进行检索以及统计,同一个事务前后执行的结果不同。使用临键锁来锁,可以保证一个范围内的数据不变,一定程度上防止幻读
1.索引上的等值查询(唯一索引),给不存在的记录加锁的时候,优化为间隙锁。也就是该不存在的记录前后两个记录的间隙
2.索引上的等值查询(普通索引--》数据可重复),向右遍历最后一个值不满足查询需求时,next-key退化为间隙锁
还是以该图为例,例如查询18的时候,我们需要在16-18以及18-29之间添加间隙锁,因为他们不是唯一索引,需要锁住范围防止18又添加几个
3.索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止
例子如下,如果我们查询的记录时>=94
第一个不满足的值时98,此时会加什么锁?
首先94添加一个行锁,随后98添加临键锁,也就是锁98和前面的范围,以及正无穷添加一个临键锁(正无穷以及其前面的所有范围。