理解MySQL的锁

120 阅读4分钟

全局锁

全局锁是怎么用的

flush tables with read lock

执行上述命令后,整个数据库处于只读状态,执行除了读操作以外的操作都会被阻塞

unlock tables

执行上面的命令就可以释放全局锁,会话断开也会自动释放全局锁

全局锁的应用场景

全局锁主要应用于全库逻辑备份,这样在备份数据库期间不会因为其它的操作导致备份文件的数据与预期不一样。

全局锁的缺点

加上全局锁以后,对数据库的操作只能是读操作,如果数据库中数据量大,备份时间就会长,在这一段备份时间内只能读数据而不能更新数据,会造成业务停滞

备份数据库时如何避免影响业务

如果数据库中有支持事务的引擎,如InnoDB,那么在备份数据库之前可以先开启事务,InnoDB的隔离级别默认是可重复读,在此隔离级别下,即使其它事务更新了表,也不会影响到备份的数据。

但是对于不支持事务的引擎,如MyISAM,在备份数据库时就需要使用全局锁。

表级锁

MySQL表级锁

  • 表锁
  • 元数据锁(MDL)
  • 意向锁
  • AUTO-INC锁

表锁

加锁

//表级别的共享锁,读锁
lock tables 表名 read;
//表级别的独占锁,写锁
lock tables 表名 write;

释放锁

unlock tables

会话退出后也会自动释放所有表锁

加了锁后,表锁会限制所有线程的读写操作,包括本线程。

避免在使用InnoDB引擎的表使用表锁,因为表锁的颗粒度太大,会影响并发性能,InnoDB实现了颗粒度更细的行级锁

元数据锁

MDL不需要显式调用,当我们对数据库表进行操作时,会自动给这个表加上MDL,对表数据进行更新时会加MDL读锁,对表结构进行修改时会加MDL写锁。

写锁获取优先级高于读锁

MDL是为了保证用户对表数据进行更新时防止其它线程对表结构做了变更。

那么MDL是在什么时候释放的?

MDL在事务提交后才会释放,在整个事务期间一直持有MDL。

意向锁

在使用InnoDB引擎的表里对某些记录

  • 加上共享锁之前,需要先在表级别加上一个意向共享锁
  • 加上独占锁之前,需要先在表级别加上一个意向独占锁 当执行增删改操作时,先要对表加上意向排它锁,然后对该记录加独占锁

而select是利用MVCC实现一致性读,是无锁的

意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables … read)和独占表锁(lock tables … write)发生冲突。

如果没有意向锁,那么加独占表锁时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。那么有了意向锁,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加独占表锁时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。所以,意向锁的目的是为了快速判断表里是否有记录被加锁

AUTO-INC 锁

在为某个字段声明 AUTO_INCREMENT属性后,在插入数据时数据库会自动给该字段赋值递增的值,这个主要是通过AUTO-INC 锁实现的

AUTO-INC锁是特殊的表锁机制,在执行完插入语句后就立即释放。

AUTO-INC锁在大量数据插入的时候,会影响插入性能。因此在MySQL5.1.22版本开始,InnoDB引擎提供了一种轻量级的锁来实现自增。在插入数据时,会为被AUTO_INCREMENT声明的字段加上轻量级锁,然后赋值一个自增的值后就释放锁,不需要等待整个语句插完后才释放锁。

行级锁有哪些

InnoDB是支持行级锁的,MyISAM不支持。 行级锁主要有三类:

  • Record Lock,记录锁 : 把一条记录上锁
  • Gap Lock 间隙锁: 锁定一个范围,不包含记录本身
  • Next-Key Lock,以上两种锁的组合,锁定一个范围的同时锁定记录本身