mysql各种锁

包括全局锁、表锁(表锁、元数据锁、自增锁)、行锁(行锁、间隙锁、临键锁、共享锁、排他锁、意向锁、插入意向锁)

 

一、全局锁(FUWRL)

语句为:Flush tables with read lock   。可以对整个数据库实例加锁,让整个库处于只读状态。使用场景是全库逻辑备份时。

还有一种全局锁方法是set global readonly=true(不建议用),原因:

  1. readonly值用来判断主从库时无效。
  2. 如果出问题。FUWRL方法当客户端断开就自动释放了全局锁,而readonly不会。
  3. 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)减少锁冲突或死锁的方法:

  1. 使用较低的隔离级别。
  2. 使用索引访问数据。
  3. 事务尽量小。
  4. 显式加锁时,最好一次请求够足够级别的锁。比如:修改数据时,直接请求排他锁。而不是先请求共享锁,再请求排他锁。容易死锁。
  5. 不要申请超过实际需要的锁的级别。不建议显式加锁。例如:行锁可以解决,非要申请表锁
  6. 对于特定事务,可以直接申请表锁来提高处理速度,减小死锁的可能。

猜你喜欢

转载自blog.csdn.net/sumengnan/article/details/112727820