MySQL 锁类别

全局锁

flush tables with read lock;
unlock tables; // 解锁

这样表就处于只读状态了,全库逻辑备份就需要用这个。

表级锁

表锁

lock tables `table_name1` read, `table_name2` read; # 读锁
lock tables `table_name` write, `table_name2` write; # 写锁
unlock tables; # 解锁或者退出会话自动解锁
  • 读锁:只能对当前表进行读,不能对当前表进行写,也不能访问其他表。其他会话只能读这张表,不能写这张表。

元数据锁

元数据锁(MDL)

  • 对一张表进行crud,加上MDL读锁。

  • 对一张表结构进行改变,会加上MDL写锁。

MDL是自动上锁自动解锁的,整个事务期间都会有

意向锁

当加行级锁(如增,删,改时)会先加上表级别的意向锁,这样如果需要加表锁的话,可以通过检查意向锁而不需要逐行检查表锁,加快速度。

  • 意向共享锁:对行级别加共享锁之前,需要对表级别加意向共享锁。
  • 意向独占锁:对行级别加独占锁之前,需要对表级别加意向独占锁。

AUTO-INC锁

主键自增时也会发生重读,auto-inc锁就是为了主键自增设计的锁,可以更改环境变量innodb_autoinc_lock_mode来改变锁的行为

  • innodb_autoinc_lock_mode=0,语句执行结束后才释放
  • innodb_autoinc_lock_mode=2,轻量级锁,主键增加后就释放
  • innodb_autoinc_lock_mode=1
    • 普通select锁,申请后马上释放
    • insert ... select批量插入语句,等语句结束才释放

行级锁

InnoDB支持行级锁,MyISAM不支持。

普通select不会加锁,因为属于快照读,只需要MVCC即可。在事务中,才会进行锁定读,可以使用如下命令:

select ... lock in share mode;  -- 共享锁
select ... for update; -- 独占锁

事务提交了,锁就会释放了。

  • Record lock:记录锁,锁住某一条记录。分为共享锁(S)和独占锁(X)之分。
  • Gap lock:间隙锁,锁定某个范围(开区间,不会锁定记录本身),只有共享锁,但是会阻塞insert语句
  • Next-Key Lock:记录锁+间隙锁,锁定一个返回(可以为前开后闭区间,也会锁定记录本身),有共享锁(S)和独占锁(X)之分,并且对范围内的记录都是有独占锁和共享锁之分的。
  • 插入意向锁:在插入数据时,如果被其他事务的锁阻塞了,那么就会设置一个插入意向锁,它是一个特别的间隙锁,与间隙锁是互斥的。

加锁规则

行级锁是以next-key lock作为基本单位的,next-key lock是前开后闭区间,间隙锁是开区间

  • 唯一索引等值查询
    • 记录存在,那么就是对该条记录加锁,退化成记录锁
    • 记录不存在,那么找到第一个大于该记录并加锁,退化成间隙锁
  • 唯一索引范围查询
    • 针对>=查询时:由于等值存在,所以会退化成记录锁
    • 针对</<=查询时:
  • 非唯一索引等值查询
  • 非唯一索引范围查询