锁的定义与作用
多用户环境下,当多个事务同时访问相同的数据时,可能会引发问题,锁就是用于协调多个线程并发访问数据库资源的机制,为了保证数据的一致性和准确性。
锁的类型
-
共享锁(Shared Lock/S Lock):
-
用于读取操作(如
SELECT
)。 -
允许多事务同时持有,但阻止其他事务获取排他锁。
-
-
排他锁(Exclusive Lock/X Lock):
-
用于写入操作(如
UPDATE
,DELETE
)。 -
仅允许一个事务持有,其他事务无法获取任何类型的锁。
-
-
意向锁(Intention Locks):
-
意向共享锁(IS):事务计划在更细粒度(如行级)加共享锁。
-
意向排他锁(IX):事务计划在更细粒度加排他锁。
-
意向锁在表级设置,用于快速判断表中是否存在行级锁,避免逐行检查。
-
锁的粒度
全局锁:
1.定义:
针对整个数据库实例上的锁,加锁后该实例只允许读操作,对DDL(数据定义语言:定义/改变表的结构、数据类型、表之间的链接等操作。常用的语句关键字有 CREATE、DROP、ALTER 等)和DML(数据操作语言:主要是对数据进行增加、删除、修改操作。常用的语句关键字有 INSERT、UPDATE、DELETE 等)只能阻塞等待锁释放。
2.使用场景:
对数据库进行逻辑备份时,需要添加全局锁,避免出现备份期间,DDL和DML对数据库修改,导致数据出现不一致。
3.具体操作:
添加全局锁:
flash tables with read lock;
数据备份:
使用mysql提供的工具mysqldump,不是SQL语句,所以不能在>mysql输入,而是直接在命令行
mysqldump -u用户名 -p密码 备份sql路径
mysqldump -uroot -p123456 D:/db.sql
释放全局锁:
unlock tables
4.特点
添加全局锁后,增删改操作阻塞,业务基本停止;
使用InnoDB引擎,可以在备份参数添加--single-transaction参数来完成不加锁的一致性数据备份:
mysqldump --single-transaction -uroot -p123456 D:/db.sql
表级锁:
每次操作锁住整张表,锁的粒度大,发生锁冲突的概率最大,并发度最低。
表锁
1.定义
表共享读锁(read lock):允许当前客户端读,阻塞写;允许其他客户端读,阻塞写;
表共享写锁(write lock):允许当前客户端读和写;不允许其他客户端读和写。
2.语法
lock tables table1 read
lock tables table1 write
元数据锁(MDL)
元数据:描述数据的数据。在数据库中,元数据是指描述数据库对象(如表、列、索引等)结构的信息。
MDL加锁过程是系统控制,无法直接干预。
1.作用
维护表元数据的数据一致性,当表上有活动事务时,不允许对元数据进行修改操作。避免DML(数据操作语言)和DDL(数据定义语言)的冲突。
DML会申请MDL读锁(共享);DDL申请MDL写锁(排他)。
|-------|-------|-------|
| | MDL读锁 | MDL写锁 |
| MDL读锁 | 允许 | 阻塞 |
| MDL写锁 | 阻塞 | 阻塞 |
意向锁
在添加表锁时,要先检测是否添加了行锁,所以就要检测每一行数据,非常的麻烦。
1.作用
意向锁可以解决这个问题,当添加行锁时,同时添加一个意向锁暴露出来,表锁就不需要遍历查找行锁了。
2.类型
|-----------|-------|-------|
| | 表共享读锁 | 表共享写锁 |
| 意向共享锁(IS) | 允许 | 阻塞 |
| 意向排他锁(IX) | 阻塞 | 阻塞 |
意向锁之间不互斥。
行级锁
每次操作只锁住对应的行,锁的粒度小,发生锁冲突的概率低,并发度最高。
Innodb和myisam的一个差别就是锁。
默认情况下,Innodb在Repeatable Read(可重复读)事务隔离级别运行,Innodb使用next-key锁进行索引扫描,避免幻读。
行锁(Record Lock)
1.定义:
锁住单行数据,防止其他事务对它进行update和delete操作。
2.使用:
对唯一索引进行检索时,对数据进行等值匹配时,自动优化为行锁;
Innodb的行锁是针对索引的,如果不使用索引查询条件,那么Innodb会对所有的数据加锁,则自动变成表锁。
间隙锁
1.定义
添加索引的数据不一定是连续的,比如id可以是1,2,5,9,88...
当给索引key的间隙加锁时,就是间隙锁。
比如,update ......where id = 7,就锁住了(5,9)
2.作用
不锁行数据,锁间隙有什么用,作用就是避免幻读,防止其他事务插入空隙。
我开启事务1,对id=9的行上行锁修改行数据,同时开启事务2,对id=7的行进行新增数据。
事务1:
update ......where id = 9;
事务2:
insert ......where id =7;
两个事务提交都会成功,就会出现幻读。
注意:间隙锁不互斥
临键锁
行锁+间隙锁