包括全局锁、表锁(表锁、元数据锁、自增锁)、行锁(行锁、间隙锁、临键锁、共享锁、排他锁、意向锁、插入意向锁)
一、全局锁(FUWRL)
语句为:Flush tables with read lock 。可以对整个数据库实例加锁,让整个库处于只读状态。使用场景是全库逻辑备份时。
还有一种全局锁方法是set global readonly=true(不建议用),原因:
- readonly值用来判断主从库时无效。
- 如果出问题。FUWRL方法当客户端断开就自动释放了全局锁,而readonly不会。
- readonly对super用户无效
其实我们备份库还可用mysqldump --single-transaction,导出数据之前会启动一个事务,来确数据一致性。有于MVCC支持,这个过程数据是可以正常更新的。
但是不是所有的引擎都支持事务,如MyIsam引擎。
二、表锁
(1)表锁
InnoDb引擎要将AUTOCOMMIT设为0
加锁语法 :lock tables ……read/write
解锁语法:commit语句+ unlock tables语句
示例:
SET AUTOCOMMIT=0;
LOCAK TABLES t1 WRITE, t2 READ, ...;
COMMIT;
UNLOCK TABLES;
注意:当存储引擎为InnoDb时,表锁不是由InnoDb管理的而是上层Mysql server负责的,仅当autocommit=0、innodb_table_lock=1时,Innodb才能自动检测并处理表级的死锁
(2)元数据锁(MDL)(Metadata Lock)
mysql5.5后,用于解决DDL与DML操作一致性的问题。MDL锁不需要显式使用。当对一个表执行DML语句时(增删改查)时加MDL读锁。当执行DDL语句时(修改表结构)加MDL写锁。
读读锁之间不互斥,可以同时对一张表增删改查操作。读写锁、写写锁之间互斥,不可以同时修改表结构,只能按顺序执行。
所以当我们操作生产环境,例如给表加字段时,注意互斥问题可能会把表锁了。可以选择低峰期添加字段。或是查看是否有长事务在执行,等待或kill掉。
注意:MDL锁没有超时时间的限制。
(3)自增锁(AUTO-INC Locks)
是一种特殊的表级锁,涉及AUTO_INCREMENT列的事务性插入操作是产生。
三、行锁
(1)行锁(Record Lock)
InnoDB的行销是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁(所以说where后的列需要加索引)
行锁锁定的是索引记录,而不是行数据,也就是说锁定的是key
(2)间隙锁(Gap Lock)
锁定索引记录的间隙,确保索引间隙不变。(阻止其他事务的插入操作,防止幻读发生。),针对可重复读或以上隔离级别
举例:假如索引记录中包含1,10 ,100。则会包含4个间隙(前开后闭的区间):
- (negative infinity, 1]
- (1, 10]
- (10, 100]
- (20, positive infinity)
(5)临键锁(Next Key Lock)
行锁和间隙锁组合的结果。语法: select …… for update;
InnoDB在可重复读隔离级别下,会以Next-Key Lock方式对数据行进行加锁。扫描索引记录时会先对索引记录加上行锁(Record Lock),再对索引两边间隙加上间隙锁(Gap Lock)
当查询的索引含有唯一属性时,该锁会降级为Record Lock,仅锁索引本身。还有其他降级场景:
场景 | 降级后锁类型 |
唯一索引=匹配,且记录存在 | 行锁Record Lock |
唯一索引=匹配,且记录不存在 | 间隙锁Gap Lock |
唯一索引范围匹配(<和>) | 临键锁,锁上界,不锁下界 |
(3)共享锁(SHARED Lock)(S锁)
语句:select …… lock in share model; 共享锁表示本事务可读可写,其他事务可读不可写。
(4)排他锁(EXCLUSIVE Lock)(X锁)(互斥锁)
语法: select …… for update;排他锁表示本事务可读可写,其他事务不可读不可写。
(6)意向锁(Intention Lock)
意向锁是InnoDB自动加,无需人工干预。
- 意向共享锁(IS):事务准备给数据行加入共享锁。加锁之前先取得该表的IS锁。
- 意向排他锁(IX):事务准备给数据行加入排他锁。加锁之前先取得该表的IX锁。
(7)插入意向锁(Insert Intention Lock)
插入意向锁实际上是一种间隙锁,在insert时产生。允许多个事务同时插入同一个索引间隙内不同的数据值
三、页面锁
引擎BDB使用。直接锁定整张表,其他进程无法对该表进行写操作。如果是写锁,则其他进程读也不允许。
其他:
(1)查看 InnoDB 监控中关于锁的事务数据的方法
使用SHOW ENGINE INNODB STATUS命令
(2)减少锁冲突或死锁的方法:
- 使用较低的隔离级别。
- 使用索引访问数据。
- 事务尽量小。
- 显式加锁时,最好一次请求够足够级别的锁。比如:修改数据时,直接请求排他锁。而不是先请求共享锁,再请求排他锁。容易死锁。
- 不要申请超过实际需要的锁的级别。不建议显式加锁。例如:行锁可以解决,非要申请表锁
- 对于特定事务,可以直接申请表锁来提高处理速度,减小死锁的可能。