MySQL-锁

全局锁 FTWL

使用全局锁后数据库只允许读不允许写。

# 1. 
FLUSH TABLE WITH READ LOCK; # 加锁

UNLOCK TABLES;# 解锁

# 2. 
SET GLOBAL READ_ONLY=TRUE

# 第一种方式在客户端断开后会自动释放

表锁

MyISAM引擎只有表锁。
表锁分为两种 LOCK命令加锁和MDL锁

LOCK锁

通过LOCK命令加锁

LOCK TABLE user_job READ; # 本线程和其它线程只能读表
LOCK TABLE user_job WRITE; # 本线程可以读写,其它线程不能读写

UNLOCK user_job; 解锁

MDL锁

MDL锁 metadata lokc 即元数据锁,5.5之后引进的表级锁,保证读写正确性。

MDL锁不能手动添加,由MySQL自动添加:

  1. 对表作增删改查,加MDL读锁。
  2. 对表结果作变更操作时,加MDL写锁。
    MDL锁会在事务提交后自动释放。

MDL读锁不互斥,可以对表加多个MDL读锁,读写锁之间互斥。

MDL锁是在Server层实现的。

行锁

  1. 行共享锁
    Shared Lock 又叫做S锁。一条数据加了S锁之后,其它事务也可以读数据,共享一把锁。
select * from user_job where id = 1 LOCK IN SHARE MODE
  1. 行排他锁
    Exclusive Lock,又称为写锁,X锁。一条数据加了X锁后,其它事务只能阻塞。
    修改数据,insert, update,delete时MySQL自动加排它锁。
select * from user_job where id =1 for update

意向锁

InnoDB行锁和表锁是可以共存的,当加表锁的时候需要遍历每一行看是否有行锁,效率会降低。为解决这个问题引入了意向锁。

  1. 意向共享锁
    Intention Shared Lock 意向共享锁 IS锁
  2. 意向排他锁
    Intention Exclusive Lock 意向排它锁 IX锁

意向锁右MySQL自动维护:

  1. 当对行数据加S锁时,对整个表加IS锁
  2. 当对行数据加X锁时,对整个表加IX锁
    当加表锁时执行检查是否有意向锁即可。

    IX锁与X锁和S锁互斥,Is锁与X锁互斥,与S锁共享。

InnoDB如何解决幻读问题

通过行数来解决。锁住的时索引,没有索引时锁表。

辅助索引被锁后,对应主键索引也会被锁,InnoDB主键索引即数据。主键索引被锁整条数据都会被锁。
即便覆盖索引也会锁整条数据。

行锁有三种算法:记录锁,间隙锁和临键锁,MySQL就是通过临键锁解决幻读问题。

  1. 记录锁:Record Lock,即锁住一条数据
  2. 间隙锁: Gap Lock, 索引间隙上的锁。匹配记录的第一条的上一条到最后一条的后一条的中间,开区间。如当where 条件时范围时,整个范围都会被锁,这也造成不存在的记录也会被锁定。
  3. 临键锁:Next-Key Lock , 记录锁和间隙锁的结合。区间左开右闭,范围查询时,会锁住记录和间隙,InnoDB行锁的默认算法。
    RR级别才会有临键锁,RC只有记录锁。

行锁的加锁规则

  1. MySQL默认是RR级别,使用临键锁
  2. 使用主键或唯一索引命中一条记录的时候会退化为记录锁。
  3. 没有命中记录会退化为间隙锁
  4. 查找过程访问到对象时才会加锁
  5. 索引上进行等值查询时,向右遍历发现最后一个值不满足条件的时候,临键锁会退化为间隙锁。

乐观锁和悲观锁

乐观锁:保持乐观的态度,认为不会修改数据,默认不上锁,在执行更新时才会判断别人是否也修改了数据,是则撤销操作,反之执行。
冲突比较少的时候, 使用乐观锁(没有悲观锁那样耗时的开销) 由于乐观锁的不上锁特性,所以在性能方面要比悲观锁好,比较适合用在DB的读大于写的业务场景。
悲观锁:悲观态度,认为会修改数据,先上锁再操作。
读取频繁使用乐观锁,写入频繁使用悲观锁。

posted @ 2022-09-11 20:35  店里最会撒谎白玉汤  阅读(34)  评论(0编辑  收藏  举报