跟孙哥学java
概述
介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(cpu,ram,/0)( 种供许多用户共享的资源。如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访性能的一个重要因素,从这个角度来说,锁对数据而言尤为重要。 分类 在MySQL中,按照的锁的粒度可以分为 1.全局锁---锁定数据中的所有的表 2.表级锁---每次操作锁住整张表 3.行级锁---每次操作锁住对应的行数据
全局锁
介绍 锁粒度最大的锁----对整个数据库实例加锁,加锁后整个数据库就处于只读状态。后续DML,DDL语句都处于阻塞状态 用途---做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。 也就是在备份的过程中,如果不加全局锁,可能导致数据不一致,所以就要加全局锁来保证数据的一致。 使用
flush tables with read lock;--加全局锁
mysqldunp -uroot -p1234 itcast>itcast.sql --备份 itcast数据库--存到itcast.sql文件中
unlock tables; 解锁
- 加锁
- 只能查询不能更改
更新操作一直在阻塞
- 备份数据库
备份成功
- 释放锁
释放之后,上面的更新语句也不阻塞了
执行成功---正常运行了
特点 数据库加了全局锁,是一个比较重的问题,存在以下问题:
- 如果在主库上备份,那么在备份期间就不能执行更新,业务基本上就不能正常运行
- 如果在从库上备份,那么备份期间就从库就不能执行主库同步过来的二进制文件(binlog),会导致主从延迟
在InnoDB引擎中,我们可以在备份的时候加上参数 --single-transaction 参数来完成不加锁的一致性数据备份
表级锁
介绍 表级锁,每次操作就是锁住整张表。锁定的粒度大,发生锁冲突的概率高,并发度最低。应用在MyISAM,InnoDB,BDB等存储引擎中
对于表级锁又可以分为三类:
- 表锁
- 元数据锁
- 意向锁
表锁 对于表锁,分为两类:
- 表共享读锁 (read lock)
代码演示
1.加表共享读锁
2.客户端都可以进行查询操作
3.不能进行更新操作
MySQL报错---user表加了READ锁,不能修改
4.而其他的客户端是出于阻塞状态---直到加锁的客户端释放表共享读锁
修改成功了
- 表独占写锁 (write lock)
代码演示:
1.一个客户端加表独占写锁
2.加独占写锁的客户端,可以进行查询和修改
3.其他客户端不能读也不能写
出于阻塞状态
4.释放独占写锁
处于阻塞状态的客户端也查询到数据了
元数据锁(meta data lock ,MDL)
MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。
主要作用:为了避免DML与DDL冲突,保证读写的正确性。
在MySQL5.5中引入MDL。当我们对一张表进行增删改查的时候,加MDL读锁(共享);当我们对表结构进行变更操作的时候,加MDL写锁(排他)。
共享读/写锁
两个客户端--A,B
A,开启事务,并且进行查询操作
这时候,加了元数据锁---共享读锁
B开启事务,可以进行读写操作
这时候-B进行了写操作--->也就是加上了共享写锁--->A客户端不能进行修改操作了
排他锁
A开启事务,进行查询操作
B客户端尝试修改表的结构
阻塞了
A客户端提交事务
修改成功了
查询元数据锁, 这是在prorformance_schema这个库中 所以先得use prorformance_schema
select object_type,object_schema,object_name,lock_type,lock_duration from metadata_locks;
这时候我们没有进行增删改查,也就没有元数据锁
当我们在A客户端开启事务,进行读操作
再次查询元数据锁
这时候就有元数据锁
这时候让B客户端再开启事务,执行修改操作
再次查询元数据锁
由此可见--->共享读锁和共享写锁可以共存
如果我们进行修改表操作(会加入排他锁)
处于阻塞状态--->不能添加排他锁
由此可见--->共享读锁,共享写锁与排他锁互斥
意向锁
这样判断效率太低了----->引入了意向锁
意向锁分类
- 意向共享锁(IS) :由语句 select ...lock in share mode添加
- 意向排他锁(IX):由 insert ,update,delete,select .. for update 添加
上述就是加的意向排他锁
- 意向共享锁(IS) :与表锁共享锁(read)兼容,与表锁排他锁(write)互斥
- 意向排他锁(IX):与表锁共享锁(read)以及排他锁(write)都互斥。意向锁直接不会互斥
查询意向锁
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from data_locks;
代码演示:
查询意向锁
加入写锁成功。
这时候,我们再次对表进行加读写锁试试
由此说明了: :::info 意向共享锁(IS):与表共享锁(read)兼容,与与表独占写锁(write) 互斥 意向排他锁(IX):与表共享读锁(read),表独占写锁(write)都互斥 :::
行级锁
介绍 行级锁,每次操作锁住的是对应 行数据。锁粒度最小,发生锁的冲突的概率最小,并发度高。应用在InnoDB中 loDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:
- 行锁:锁定单个行记录的锁,防止其他事务对此进行update和delete。在RC,RR隔离级别下都支持。
- 间隙锁:锁定索引记录间隙(不含该记录),确保索引间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。
- 临键锁:行锁和间锁 的组合,同时锁住数据,并且锁住数据前面 的间隙。在RR隔离级别在支持。
行锁 InnoDB实现了两种类型的行锁:
- 共享锁(S) :允许一个事务去读一行,阻止其他事务活的相同数据集的排它锁。
- 排他锁(X):允许获取排他锁的事务跟新数据,阻止其他事务活的相同数据集的共享锁和排他锁。
代码-演示
默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索扫描,以防止幻读。
1.针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。
2.InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么InnoDB:将对表中的所有记录加锁,此时就会升级为表锁。
通过
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from data_locks;
既可以查询行锁,又可以查询意向锁。
可以看到没有加行锁
不能加入排它锁
:::info
因此:
行锁中共享锁与共享锁兼容,与排他锁互斥
排他锁与共享锁和排他锁都互斥
:::
第二种情况:
当我们给name加上索引--->再重复上述代码
:::info
因此:
行锁是根据索引加锁
:::
间隙锁/临键锁-演示 默认情况下,InnoDB:在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。 1.索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。 2.索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。 3.索引上的范围查询(唯一索引)-会访问到不满足条件的第一个值为止。
我们user表此时的结构:
1.给不存在的记录加锁-->优化成间隙锁
2,普通索引---向右遍历时,最后一个直不满足查询条件时候,next-key退化成间隙锁
- 唯一索引-使用范围查询--->也会转为间隙锁
注意:间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。