MySQL锁

MySQL锁_第1张图片

1、全局锁

什么是全局锁
MySQL的锁定主要分为全局锁、表锁和行锁
全局锁是针对整个数据库的锁,全局锁又分为读锁和写锁。
1.读锁(共享锁)该锁会阻止其他用户更新数据库,只允许读数据库。使用该锁在一段时间内可以保持数据一致性。
2.写锁(排他锁)该锁会阻止其他用户读数据和写数据。如果在修改数据的时候不想被其他用户干扰,可以使用该锁。

使用场景:一些确保整个数据库一致性的操作,比如全库备份,全库导出。

在MySQL中可以用使用FLUSH TABLES WITH READ LOCK(FTWRL)添加全局读锁,这将阻止其他线程进行的更新操作。使用UNLOCK TABLES释放锁定。注意:全局锁的开销很大,因为它会阻止其他线程的修改操作,并且在高并发场景下会导致大量的线程等待锁定,应尽量避免在生产环境使用全局锁或减少全局锁持有的时间。

样例
此时只能读不能执行写操作
MySQL锁_第2张图片
此时可以执行写操作
MySQL锁_第3张图片

2、表级锁

表级锁开销小加锁快,不会出现死锁,锁定颗粒度大,出现锁冲突概率高并发度低。

在MySQL中对MyISAM读操作会自动加上读锁,对MyISAM的写操作会自动加上写锁,因为MyISAM不支持事务在高并发场景下没办法保持数据的一致性。

InnoDB在必要情况会加表锁,但主要使用行锁来实现多版本并发控制,它能够提供更好的并发性能和更少的锁冲突。

表锁读操作多,写操作少的场景。当并发高或者写操作多表锁会成为瓶颈。

哪些命令会发生锁表

  1. ALTER TABLE修改表结构,MySQL需要锁定整张表防止在更改过程中有新的数据写入。

  2. DROP TABLETRUNCATE TABLE MySQL需要锁定整张表防止在更改过程中有新的数据写入。

  3. LOCK TABLES显式地为一个或多个表加上读锁或写锁。例如,LOCK
    TABLES t1 WRITE t2 READ;命令会给表t1加上写锁,给表t2加上读锁。

  4. 全表扫描或大范围扫描`对于MyISAM存储引擎,全表扫描或大范围扫描会触发表锁。

  5. FLUSH TABLES WITH READ LOCK(FTWRL)这个命令可以给所有表加上全局读锁,其他会话在此期间不能对数据进行修改。

加上读锁不能执行写操作。但是可以读。
MySQL锁_第4张图片
MySQL锁_第5张图片

加上写锁,已经卡死不能执行读操作。但是可以执行写操作。
MySQL锁_第6张图片
MySQL锁_第7张图片

MySQL表锁风险点

  • 性能下降
  • 并发性能差
  • 可能导致锁等待和超时
  • 写操作影响大
  • 死锁的可能性

3、行锁

对数据库表中单独一行进行锁定。开销大加锁慢会出现死锁,锁定颗粒小出现锁冲突概率低,并发度高。

行锁只能在事务中使用,也就是说只有一个事务开始后并在事务提交或回滚之前,才能对数据进行锁定。如果在非事务环境中执行sql,那么InnoDB会在语句执行结束后立即释放所有的锁。

使用场景
高并发读写操作:在高并发读写操作场景中,行级锁可以提高性能和并发性,因为它允许多个事务并发操作不同的行。
单行操作:对单行数据进行增删改操作。
短期锁:短时间锁定某行数据,行级锁可以防止长时间阻塞其他事务。
实现并发控制:确保数据的一致性和隔离性的事务中。
复杂事务处理:对多行数据进行复杂事务处理中,可以使用行级锁来锁定这些行,防止在事务处理过程中数据被其他事务修改。

发生行锁的命令

  1. select field from table for update:这种查询会对选定的行添加一个排他锁(X),那么其他事务就不能对这行数据执行写操作,也不能添加共享锁。

[video(video-1NuL7PQd-1702997559118)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=452384717)(image-https://img-blog.csdnimg.cn/img_convert/f3924b83fb438bca02423313f8090285.jpeg)(开启事务时为一行数据加排他锁,其他线程就不能修改该条数据,只有事务提交后其他线程才可以对该条数据执行写操作)]

  1. select field from table lock in share dome: 添加一个共享锁(S),那么其他事务就不能对这行数据执行写操作,但能添加共享锁。
  2. insert 会自动添加排他锁(X)
  3. update 会自动添加排他锁(X)
  4. delete 会自动添加排他锁(X)

行锁的风险

  • 死锁:两个或者多个事务都在等待对方释放资源
  • 锁升级:如果一个事务锁定的行过多,InnoDB可能会将行锁升级为表锁,就会造成更多的锁冲突。
  • 锁等待:如果一个事务锁定了某行,其他事务要想访问该条数据,就必须等待该条数据事务已提交事务。
  • 资源消耗:行锁需要更多的内存存储锁信息,而且需要更多的CPU时间来处理锁请求和释放锁。如果数据库中的行锁很多,或者并发事务很多就会消耗大量资源。
  • 难以调试和排查:行级锁粒度小,如果出现性能问题或者锁冲突很难进行排查。
  • 事务隔离级别:不同的事务隔离级别会影响锁的行为和性能,可能需要根据具体应用场景来调整事务隔离级别

4、乐观锁

是一种在数据库操作中用于处理并发请求的技术。事务操作该条数据前不会立即加锁,而是在数据更改时检查其他事务是否修改了该条数据。如果没有则提交事务,否则回滚。

使用场景

  • 低冲突环境
  • 读多写少的环境
  • 短事务操作

实现方式
通过数据库字段,版本号字段或者时间戳字段。每次修改前把版本号或者时间戳查出来,where 条件带上版本号或者时间戳查,是否是刚才查出来的结果

5、悲观锁

认为数据在并发处理中一定会被其他事务修改,每次在读数据时都会先加锁,这样可以避免其他事务在并发处理中的读写操作。

使用场景
悲观锁具有先加锁的特点适合一下场景

  • 写数据比较多的场景:写操作多的场景数据冲突概率更高,预先加锁后其他事务就不能对该数据执行写操作。
  • 并发冲突高的场景
  • 业务需要强一致性的场景

实现方式

  • select field from table where id = 1 for update:意思是给id为1的数据加上排他锁,这样其他事务就不能修改该条数据也不能为该行数据重新设置排他锁或者共享锁。

  • select field from table where id = 1 lock in share mode:意思是给id为1的数据加上共享锁,其他事务可以读该条数据但是不能写,也不能为其重新设置排他锁。

6、意向共享锁和意向排他锁

意向锁是表锁,为了协调表锁和行锁的关系,支持多粒度(表锁与行锁)的锁并存。

作用
当事务A有行锁时,MySQL会自动为该表添加意向锁,事务B如果想申请整张表的写锁,那么不需要遍历每一行判断是否存在行锁,而是直接判断是否存在意向锁,增强性能。

为什么意向锁是表锁
当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定。
如果意向锁时行锁,则需要遍历每一行数据去确认。
如果意向锁是表锁,则只需判断一次就可以知道有没有数据行被锁定,提高性能。‘

意向锁怎么支持表锁和行锁并存
并存的概念是数据库同时支持表锁和行锁,而不是在一个表中有一个事务A持有行锁,一个事务B只有表锁。因为一个表一旦持有表锁,就不能再加上一个行锁。
如果事务A对某一行数据上锁,其他事务就不能修改改行数据。所以在没有意向锁的时候让表锁和行锁共存会带来很多问题。数据库不需要检查每一行数据是否有锁,而是直接判断是否存在意向锁。

意向锁的兼容互斥性
MySQL锁_第8张图片

7、临键锁

临键锁可以解决幻读问题。每个数据行上的非唯一索引列都会存在一个临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭的数据。InnoDB中的行级锁时基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键)不存在临键锁。
MySQL锁_第9张图片
该表中存在的临键锁有
(-∞,10]
(10,24]
(24,32]
(32,45]
(45,+∞]

实现方式

  1. 开启事务,并为age=32设置排他锁锁。age为非唯一索引
    MySQL锁_第10张图片
  2. 其他线程新增一条age=34的数据,发现阻塞无法新增
    MySQL锁_第11张图片
  3. 提交事务 MySQL锁_第12张图片
  4. 不再阻塞提交成功
    MySQL锁_第13张图片

8、记录锁

主要用于锁定和控制对单个行记录的访问。记录锁是在索引记录上设置的,对于没有主键或唯一索引的表,InnoDB会生成一个隐藏的聚簇索引,并在这个隐藏索引上加锁。

9、间隙锁

该锁锁定的不是具体的行记录,而是两个索引之间的间隙(区间)。这样可以防止新的记录插入到该间隙,确保数据的一致性和事物的隔离性。
间隙锁主要是为了解决幻读问题。

实现方式

  1. 开启事务,并未id在[1,4]区间的数据设置间隙锁
    MySQL锁_第14张图片
  2. 其他事务修改id为3的数据,发现阻塞无法修改。这是因为id为1,2,3,4的数据行都存在排他锁,其他事务无法执行写操作
    MySQL锁_第15张图片
  3. 提交事务
    MySQL锁_第16张图片
  4. 执行成功
    MySQL锁_第17张图片

你可能感兴趣的:(mysql)