[沫忘录]MySQL 锁
锁能够协调多线程或多进程并发访问某资源产生的数据冲突与错乱。而在数据库中,锁也是协调数据库访问的有效工具。
全局锁
能够锁住当前服务器所有数据库及其表。后续所有事务都只能进行读操作,而不能进行写操作或表属性更改。
典型使用场景是数据库的逻辑备份。
在数据库备份时,如果中途对还未来得及备份的表进行了一次修改,那么此时备份的数据库是修改之后的数据库,而非修改之前的数据库。更甚的是,如果该次修改还涉及已经备份了的数据,那么这次备份既包含修改后的数据,也包含修改前的数据,照成了数据的不一致性。
#数据库备份(命令行命令)
mysqldump -uroot(用户) -p1234(密码) 待备份数据库名>itcast.sql(数据库文件)
#添加全局锁
flush tables with read lock;
#关闭全局锁
unlock tables;
存在的缺点
- 当全局锁存在时,许多诸如插入数据的操作都会阻塞停摆。大幅影响并发效率。
- 当全局锁存在时,如果存在主从数据库,则对从属数据库备份时,从属数据库无法接受主数据库发来的数据,造成主从数据不同步。
表级锁
表级锁的使用频次比全局锁大,但表锁锁住整张表,粒度比较大,所以发生锁冲突的概率最高。
表锁
表锁分为表共享读锁和表独占写锁。
-
表共享读锁
所有客户端连接一律只读,其他客户端写操作阻塞。
-
表独占写锁
只允许加锁客户端读写,其他客户端操作阻塞。
#加锁
lock tables 表名 read|write;
#解锁
unlock tables;#或者直接断开客户端连接
元数据锁
元数据锁(meta data lock, MDL)加锁过程是系统自动控制,无需显示使用,主要用于避免DML和DDL冲突,保证数据读写正确性。
当对一张表进行增删改查时,加的MDL读写锁是共享的(共享即存在一种锁时是否能够添加另一种锁);当对表结构进行变更操作的时候,加MDL写锁是排他互斥的。
#查看元数据锁
SELECT object_type, object_schema, object_name, lock_type, lock_duration FROM performance_schema.metadata_locks;
元数据锁中的shared_write和shared_read不同于表锁,会对其他客户端的事务产生影响,而更多的是一种标记,主要与EXCLUSIVE的进行互斥。故不同客户端携带shared_write和shared_read并不会同表锁一样可能相会之间阻塞。
意向锁
当表中存在行级锁,再加表锁可能因表锁类型而无法加锁。而如果全表扫描是否有行锁,那么效率较低。因此我们引入意向锁来标记行锁类型,避免全表查询。
notice: 元数据锁中加锁等行为也会产生意向锁,如lock in share mode
就会对查询的元组加意向共享锁和行共享锁,数据修改则会加意向排他锁和行排他锁,这与元数据锁中的读写锁兼容有所区别。
- 意向共享锁(IS): 与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。
- 意向排他锁(IX): 与表锁共享锁(read)和表锁排他锁(write)都互斥。意向锁间不互斥。
#查看意向锁
select object_schema, object_name, index_name, lock_type, lock_mode, lock_data from performance_schema.data_locks;
行级锁
行锁基于聚集索引的索引项进行上锁,而非对表中行直接上锁。
行级锁的特点是粒度最小,并发最高。
-
行锁
- 共享锁(s): 允许一个事务读一行,阻止其他事务读此行。
- 排他锁(x): 允许加排他锁事务更新数据,阻止其他事务所有行为。
事务在默认隔离级别下,对已操作的单行加行锁。
行锁是对索引进行加锁,如若对没有索引的字段进行匹配,那么行锁将会升级成表锁。
-
间隙锁
在两个元组之间加锁,防止其他事务将数据插入到这两个元组之间。
间隙锁是能够共存的,多个事务可以对同一个间隙添加间隙锁。
-
临键锁
在对元组加行锁的同时,对元组前面的加间隙锁。
notice:
- 等值查询(含索引)时,如无法查找到该元组,则会对最后一个不满足查询的元组前面加间隙锁。
- 范围查询时,如会对最后一个不满足查询的元组前面加间隙锁,所有满足查询的元组加临键锁。
间隙锁和临键锁能够有效避免幻读现象,即其他事务新增了当前事务未曾读取的数据,如果其他事务再回滚删除该数据,则当前事务又无法查看该数据,造成数据时有时无,如同幻觉。
元组前面加间隙锁,所有满足查询的元组加临键锁。
间隙锁和临键锁能够有效避免幻读现象,即其他事务新增了当前事务未曾读取的数据,如果其他事务再回滚删除该数据,则当前事务又无法查看该数据,造成数据时有时无,如同幻觉。