mysql技术文档--mysql锁专精--锁全解!!!

 简单认识:

        在使用MySQL数据库时,锁可用于控制并发访问和修改数据库中的数据。它们确保在某个事务正在读取或修改数据时,其他事务不能同时对同一数据进行读取或修改操作。

MySQL提供了多种类型的锁,包括共享锁(Shared Locks)和排他锁(Exclusive Locks)。共享锁允许多个事务同时读取同一数据,但不允许修改该数据。而排他锁则只允许一个事务同时读取和修改数据。

锁还可以根据持有时间的长短分为短期锁和长期锁。短期锁是在事务或查询期间使用的锁,当事务或查询完成后,锁就会释放。而长期锁是在整个事务过程中一直保持的锁,直到事务提交或回滚。

在MySQL中,锁是自动管理的,通常无需手动管理锁。但需要注意的是,当并发操作非常频繁时,锁可能导致性能问题。因此,在设计数据库结构和操作时,应谨慎考虑并发访问和锁的使用,以避免潜在的性能瓶颈。

mysql技术文档--mysql锁专精--锁全解!!!_第1张图片

颗粒度分类

全局锁:

全局锁是MySQL中一种比较特殊的锁,它可以锁住整个数据库实例,以阻止其他会话对数据库进行修改。当你使用全局锁时,其他会话将无法执行任何写操作,只能执行读操作。这对于进行备份、导出数据或执行一些需要保证数据一致性的操作非常有用。

全局锁的工作流程如下:

  1. 当执行全局锁命令时,MySQL会将当前会话设置为全局锁模式。这将阻塞其他会话的写操作,但允许读操作继续执行。
  2. 全局锁被设置后,其他会话将无法获取写锁。它们可以继续读取已存在的数据,但不能修改数据。
  3. 当需要解除全局锁时,只需执行相应的命令。解除锁后,其他会话可以继续正常操作数据库。

以下是一个全局锁的案例: 假设你需要对数据库进行备份,并确保备份期间不会有任何写操作。你可以使用如下命令设置全局锁:

FLUSH TABLES WITH READ LOCK; -- 设置全局锁
SHOW MASTER STATUS; -- 执行备份操作
UNLOCK TABLES; -- 解除全局锁

在执行FLUSH TABLES WITH READ LOCK后,其他会话将被阻塞无法执行写操作,只能进行读操作。然后你可以执行相应的备份操作,比如使用mysqldump命令进行数据导出。完成备份后,使用UNLOCK TABLES命令解除全局锁,其他会话可以继续正常操作数据库。

全局锁的底层原理涉及MySQL的各个组件和线程之间的协调。当全局锁被设置时,MySQL会将数据库实例的写入操作暂停,以确保数据的一致性。这是通过操纵MySQL存储引擎的锁机制实现的。具体而言,MySQL中的InnoDB存储引擎使用了MVCC(多版本并发控制)和锁来管理并发访问和修改数据的时机。

表锁:

表锁是MySQL中的一种粗粒度锁,它锁定整个表,而不是表中的某个特定行或记录。当你使用表锁时,其他会话无法同时对同一表进行写操作,但可以进行读操作。

表锁的工作流程如下:

  1. 当一个会话请求对表进行写操作时,MySQL会检查该表是否已被其他会话锁定。如果是,请求会被阻塞,直到表锁被释放。
  2. 如果该表未被其他会话锁定,则该会话获得表锁,可以进行写操作。
  3. 在表锁释放之前,其他会话只能对该表进行读操作,不能进行写操作。
  4. 当拥有表锁的会话完成写操作后,会释放表锁,允许其他会话对表进行写操作。

以下是一个表锁的案例: 假设你有一个高并发的系统,其中有一个订单表(order),你想对该表进行结构的修改,并确保修改过程中没有其他会话能够访问该表。你可以使用如下命令来设置表级锁:

LOCK TABLES order WRITE; -- 锁定订单表
-- 进行结构修改操作
UNLOCK TABLES; -- 解锁订单表

 在执行LOCK TABLES order WRITE后,其他会话将被阻塞,无法对订单表进行写操作。这样,你就可以在安全的环境下进行表结构的修改操作。完成修改后,使用UNLOCK TABLES命令解锁订单表,其他会话可以继续对表进行操作。

表锁的底层原理是通过在MySQL服务器层实现的。当使用表级锁时,MySQL会在内部维护一个锁表,用于记录哪些表被锁定了。当一个会话请求锁定表时,MySQL会检查锁表来查看是否有其他会话在使用锁。

需要注意的是,表锁是一种比较粗粒度的锁,可能会导致并发性能问题。因此,在设计数据库结构时,尽量避免频繁使用表级锁,可以考虑使用行级锁或其他更细粒度的锁来减少对并发性能的影响。

行锁:

行锁是MySQL中的一种细粒度锁,它可以锁定表中的某一行或某几行数据,而不是整个表。行锁的使用范围更小,可以允许多个会话同时对同一表进行读写操作,只要它们操作的行不冲突即可,从而提高并发性能。

行锁的工作流程如下:

  1. 当一个会话请求对某行进行写操作时,MySQL会检查该行是否已被其他会话锁定。如果是,请求会被阻塞,直到行锁被释放。
  2. 如果该行未被其他会话锁定,则该会话获得行锁,可以进行写操作。
  3. 其他会话可以继续对表进行读写操作,只要它们不冲突。如果有会话请求锁定冲突的行,该请求会被阻塞,直到行锁被释放。
  4. 当拥有行锁的会话完成写操作后,会释放行锁,允许其他会话对该行进行写操作。

以下是一个行锁的案例: 假设你有一个在线商城系统,其中有一个商品表(products),你想同时处理两个购买请求,但不能让它们同时对同一行商品进行修改。你可以使用如下命令来设置行锁:

START TRANSACTION; -- 开启事务
SELECT * FROM products WHERE id = 1 FOR UPDATE; -- 锁定id为1的商品行
-- 执行购买操作,对商品进行修改
COMMIT; -- 提交事务

在执行SELECT * FROM products WHERE id = 1 FOR UPDATE时,会锁定id为1的商品行,阻塞其他会话对该行进行写操作。这样,你可以在事务中安全地处理购买请求,并保证商品行的一致性。完成修改后,使用COMMIT命令提交事务,释放行锁,允许其他会话继续对该行进行写操作。

行锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能使用不同的行锁策略,但一般都会使用多版本并发控制(MVCC)和锁机制来管理并发访问和修改行数据的时机。

需要注意的是,行锁可能会导致死锁情况的发生,这是因为当多个会话相互等待对方持有的锁时,可能会形成死锁循环。因此,在设计数据库结构和操作时,需要合理地使用行锁,并确保通过事务等方式避免死锁的发生。

模式分类-乐观锁、悲观锁

Mysql--技术文档--悲观锁、乐观锁-《控制并发机制简单认知、深度理解》_一单成的博客-CSDN博客

属性分类

共享锁

共享锁(Shared Lock)是MySQL中的一种锁机制,它允许多个会话同时读取同一行或同一数据集,但不允许修改数据。共享锁适用于并发读取操作,它可以提高并发性能,因为多个会话可以同时读取数据而不会产生冲突。

共享锁的工作流程如下:

  1. 当一个会话请求对某行或某个数据集进行共享锁时,MySQL会检查该行或该数据集是否已被其他会话持有排他锁(Exclusive Lock)或独占锁(Exclusive Access Lock)。如果是,则共享锁请求会被阻塞,直到排他锁或独占锁被释放。
  2. 如果该行或该数据集未被其他会话持有排他锁或独占锁,则该会话获得共享锁,可以进行读取操作。
  3. 在共享锁被设置期间,其他会话仍然可以请求并获得共享锁,允许它们同时读取数据,不会产生冲突。
  4. 当所有共享锁被释放后,其他会话将有机会请求并持有排他锁或独占锁进行写操作。

以下是一个共享锁的案例: 假设你有一个论坛系统,其中有一个帖子表(posts),多个用户可以同时读取同一篇帖子的内容。你可以使用如下SQL语句来设置共享锁:

SELECT * FROM posts WHERE id = 1 LOCK IN SHARE MODE; -- 锁定id为1的帖子行,并设置共享锁
-- 执行读取操作,读取帖子内容

 在执行SELECT * FROM posts WHERE id = 1 LOCK IN SHARE MODE时,将锁定id为1的帖子行,并设置共享锁。这样,多个会话可以同时读取帖子内容,并保证数据的一致性。完成读取操作后,共享锁会被释放,其他会话可以继续请求共享锁或排他锁。

共享锁的底层原理是通过MySQL的存储引擎实现的。存储引擎使用锁机制来管理并发访问和修改数据的时机。具体实现方式可能因存储引擎而异,一般会结合MVCC(多版本并发控制)等技术来实现共享锁的细节。

需要注意的是,共享锁是一种读取操作的锁机制,它不会阻塞其他会话的读取操作,但会阻塞写操作。因此,在设计数据库结构和操作时,需要根据实际需求和并发情况合理使用共享锁,以提高并发读取性能。

排他锁

排他锁(Exclusive Lock)是MySQL中的一种锁机制,它是一种独占锁,用于保护对数据的写操作,防止其他会话读取或修改被锁定的数据。排他锁只允许一个会话在同一时间对某行或某个数据集进行写操作。

排他锁的工作流程如下:

  1. 当一个会话请求对某行或某个数据集进行排他锁时,MySQL会检查该行或该数据集是否已被其他会话持有共享锁(Shared Lock)。如果有会话持有共享锁,则排他锁请求会被阻塞,直到共享锁被释放。
  2. 如果该行或该数据集未被其他会话持有共享锁,则该会话获得排他锁,可以进行写操作。
  3. 在排他锁被设置期间,其他会话无法请求并获得共享锁或排他锁,从而保证数据的独占性。
  4. 当完成写操作后,排他锁会被释放,其他会话有机会请求并持有锁对数据进行读取或写操作。

以下是一个排他锁的案例: 假设你有一个银行系统,其中有一个账户表(accounts),多个用户可以同时对自己的账户进行存款操作,但不允许其他用户同时读取或修改同一账户的余额。你可以使用如下SQL语句来设置排他锁:

START TRANSACTION; -- 开启事务
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 锁定id为1的账户行,并设置排他锁
-- 执行存款操作,修改账户余额
COMMIT; -- 提交事务

在执行SELECT * FROM accounts WHERE id = 1 FOR UPDATE时,将锁定id为1的账户行,并设置排他锁。这样,只有一个会话可以对该账户进行存款操作,其他会话无法读取或修改该账户的余额。完成存款操作后,使用COMMIT命令提交事务,释放排他锁,允许其他会话继续对该账户进行操作。

排他锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能使用不同的锁机制,但一般会结合行级锁、锁表等技术来管理并发访问和修改数据的时机。

需要注意的是,排他锁是一种写操作的锁机制,它会阻塞其他会话的读取或写操作。因此,在设计数据库结构和操作时,需要根据实际需求和并发情况合理使用排他锁,以保护数据的一致性和完整性。

状态分类

意向排他锁

意向排他锁(Intention Exclusive Lock)是MySQL中的一种锁机制,它与排他锁(Exclusive Lock)一起使用,用于协调多个会话对表、表分区或表分区子集的访问和锁定。意向排他锁用于控制对整个表或表的一部分进行写操作时的并发性能。

意向排他锁的工作流程如下:

  1. 当一个会话请求对表、表分区或表分区子集进行写操作时,MySQL会为该会话设置一个意向排他锁。意向排他锁并不阻塞其他会话的读取操作,但会阻塞其他会话的写操作。
  2. 当有其他会话请求对表、表分区或表分区子集进行共享锁(Shared Lock)或排他锁时,MySQL会检查该会话是否已拥有意向排他锁。如果是,则允许该会话对表、表分区或表分区子集进行读或写操作。
  3. 当有其他会话请求对表、表分区或表分区子集进行排他锁时,MySQL会检查是否已有会话拥有共享锁、意向排他锁或排他锁。如果有,则新的排他锁请求会被阻塞,直到现有锁被释放。
  4. 当所有会话释放对表、表分区或表分区子集的锁定后,新的会话可以请求并获得意向排他锁、共享锁或排他锁来进行读取或写操作。

以下是一个意向排他锁的案例: 假设你有一个社交媒体应用程序,其中包含一个用户表(users)。当有多个会话同时对用户表进行写操作(例如,更新用户信息)时,你可以使用意向排他锁来协调并发写入操作,以保证数据的一致性。

START TRANSACTION; -- 开启事务
LOCK TABLES users WRITE; -- 锁定用户表,并设置意向排他锁
-- 执行写入操作,更新用户信息
UNLOCK TABLES; -- 释放表锁
COMMIT; -- 提交事务

 

在执行LOCK TABLES users WRITE时,将锁定用户表并设置意向排他锁。这样,只有一个会话可以对表进行写入操作,其他会话的写入请求会被阻塞。完成写入操作后,使用UNLOCK TABLES释放表锁,允许其他会话继续进行读取或写入操作。

意向排他锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能会使用不同的方式来管理整个表或表分区的锁。一般来说,意向排他锁是一个表级锁,它与行级锁相互配合,以实现并发性和数据一致性。

需要注意的是,意向排他锁用于控制对整个表或表的一部分进行写操作的并发性能。在实际使用时,需要根据实际需求和并发情况合理使用意向排他锁,以提高性能并保证数据的完整性和一致性。

意向排他锁和排他锁的关系

意向排他锁(IX锁)和排他锁(X锁)都是数据库锁的一种,用于保护数据并发访问时的数据一致性和完整性。

二者的关系主要表现在以下两个方面:

  1. 请求锁的顺序不同。在对数据进行排他操作之前,需要先请求意向锁,即如果事务需要对表中的某一行进行排他性操作(如修改、删除等),那么它必须先获得该行的意向锁,否则操作无法进行。而排他锁则是对于已经获得意向锁的事务,在执行操作时自动加上排他锁,无需再次申请。
  2. 锁的兼容性不同。意向锁和排他锁在兼容性上存在差异。例如,如果一个事务对某行数据加上了排他锁,那么其他事务就无法对该行数据同时加上共享锁或意向锁,直到该事务释放了排他锁。同样的道理,如果一个事务对整个表加上了表级排他锁,那么其他事务就无法对该表同时加上意向锁或共享锁,直到该事务释放了表级排他锁。

总的来说,意向排他锁和排他锁是两种不同类型的数据库锁,它们之间的关系主要表现在请求锁的顺序和锁的兼容性上。在进行数据库操作时,需要根据实际需求合理使用不同类型的锁,以避免并发访问造成数据不一致或出现死锁等问题

意向共享锁

意向共享锁(Intention Shared Lock)是MySQL中的一种锁机制,它与共享锁(Shared Lock)一起使用,用于协调多个会话对表、表分区或表分区子集的访问和锁定。意向共享锁用于控制对数据集的读操作时的并发性能。

意向共享锁的工作流程如下:

  1. 当一个会话请求对表、表分区或表分区子集进行共享锁时,MySQL会为该会话设置一个意向共享锁。意向共享锁不会阻塞其他会话的读操作,也不会阻塞意向排他锁或排他锁的设置。
  2. 当有其他会话请求对表、表分区或表分区子集进行共享锁时,MySQL会检查是否已有会话拥有意向共享锁、意向排他锁或排他锁。如果有,则新的共享锁请求会被允许。
  3. 当有其他会话请求对表、表分区或表分区子集进行意向排他锁或排他锁时,MySQL会检查是否有会话拥有共享锁。如果有,则新的意向排他锁或排他锁请求会被阻塞,直到现有锁被释放。
  4. 当所有会话释放对表、表分区或表分区子集的锁定后,新的会话可以请求并获得意向共享锁或共享锁来进行读取操作。

以下是一个意向共享锁的案例: 假设你有一个博客系统,其中包含一篇文章表(articles)。多个会话可以同时读取相同的文章内容,但不允许写操作同时进行。你可以使用如下SQL语句来设置意向共享锁:

START TRANSACTION; -- 开启事务
SELECT * FROM articles WHERE id = 1 FOR SHARE; -- 锁定id为1的文章行,并设置意向共享锁
-- 执行读取操作,读取文章内容
COMMIT; -- 提交事务

在执行SELECT * FROM articles WHERE id = 1 FOR SHARE时,将锁定id为1的文章行,并设置意向共享锁。这样,多个会话可以同时读取文章内容,而写操作会被阻塞。完成读取操作后,使用COMMIT命令提交事务,释放意向共享锁,允许其他会话继续进行读取操作。

意向共享锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能会使用不同的方式来管理整个表或表分区的锁。一般来说,意向共享锁是一个表级锁,它与行级锁相互配合,以实现并发性和数据一致性。

需要注意的是,意向共享锁用于控制对整个表或表的一部分进行读操作的并发性能。在实际使用时,需要根据需求和并发情况合理使用意向共享锁,以提高性能并保证数据的完整性和一致性。

意向共享锁和共享锁的区别:

意向共享锁和共享锁的主要区别在于它们的用途和特性。

共享锁,也被称为读锁,是在执行读取操作时创建的。如果一个事务对数据A添加了共享锁,那么其他事务只能对数据A添加共享锁,而不能添加其他类型的锁。对于已经添加了共享锁的事务,只能执行读操作,而不能执行写操作。共享锁的使用需要在查询语句后面添加 LOCK IN SHARE MODE 指令,这样 MySQL 就会对查询结果中的每一行都加共享锁。

与共享锁不同,意向锁是表级锁,主要用于在一个事务中揭示下一行将要被请求的锁类型。在 InnoDB 中有两个表锁:意向共享锁(IS)和意向排他锁(IX)。意向共享锁表明事务准备给数据行加入共享锁,一个数据行加共享锁前必须先取得该表的 IS 锁。

综上,共享锁和意向共享锁虽然都是数据库中的锁机制,但它们的主要区别在于:共享锁主要用于在事务中保护读取操作,而意向共享锁则主要用于揭示数据行的锁定类型。

算法分类

间隙锁

间隙锁(Gap Lock)是MySQL中的一种锁机制,用于保护事务对索引范围内的间隙(两个索引键之间的空间)进行插入操作,防止其他事务在同一间隙内插入数据。间隙锁的目的是为了维护索引的一致性和完整性。

间隙锁的工作流程如下:

  1. 当一个事务对索引范围内的间隙进行插入操作时,MySQL会在间隙两端设置间隙锁,防止其他事务在同一间隙内插入数据。
  2. 当有其他事务请求在同一间隙内插入数据时,MySQL会检查是否已有事务持有该间隙锁。如果有,则新的插入操作会被阻塞,直到间隙锁被释放。
  3. 当当前事务完成插入操作后,间隙锁会被释放,其他事务可以继续在该间隙内进行插入操作。

以下是一个间隙锁的案例: 假设你有一个电子商务系统,其中包含一个商品表(products)。多个会话可以同时在指定价格范围内插入新的商品记录,但不允许商品价格在同一范围内重叠。你可以使用如下SQL语句来设置间隙锁:

START TRANSACTION; -- 开启事务
SELECT * FROM products WHERE price >= 100 AND price <= 200 FOR UPDATE; -- 锁定价格范围内的间隙,并设置间隙锁
-- 插入新的商品记录,保证价格不与已有记录重叠
COMMIT; -- 提交事务

 在执行SELECT * FROM products WHERE price >= 100 AND price <= 200 FOR UPDATE时,将锁定价格范围内的间隙,并设置间隙锁。这样,只有一个会话可以在该间隙内插入新的商品记录,其他会话在同一范围内的插入操作会被阻塞。完成插入操作后,使用COMMIT命令提交事务,释放间隙锁,允许其他会话继续进行插入操作。

间隙锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能会使用不同的方式来管理索引范围内的间隙锁。一般来说,间隙锁是一种行级锁,与其他行级锁(如共享锁、排他锁)相互配合,以实现并发性和数据一致性。

需要注意的是,间隙锁用于保护索引范围内的间隙,以防止重复插入数据。在实际使用时,需要根据需求和并发情况合理使用间隙锁,以确保数据的唯一性和一致性。

记录锁

记录锁(Record Lock)是MySQL中的一种锁机制,用于保护事务对数据行进行操作时的并发性。记录锁的作用是确保在一个事务对数据行进行读取或写入操作时,其他事务无法同时对该行进行写入操作。

记录锁的工作流程如下:

  1. 当一个事务对数据行进行读取或写入操作时,MySQL会为该数据行设置记录锁。记录锁会阻塞其他事务对同一数据行的写入操作,但不会阻塞读取操作。
  2. 当有其他事务请求对同一数据行进行写入操作时,MySQL会检查是否已有事务持有该记录锁。如果有,则新的写入操作会被阻塞,直到记录锁被释放。
  3. 当当前事务完成对数据行的读取或写入操作后,记录锁会被释放,其他事务可以继续对该数据行进行读写操作。

以下是一个记录锁的案例: 假设你有一个银行系统,其中包含一个账户表(accounts)。多个用户可以同时读取账户余额,但只允许一个用户对账户进行转账操作。你可以使用如下SQL语句来设置记录锁:

START TRANSACTION; -- 开启事务
SELECT balance FROM accounts WHERE account_number = '123456789' FOR UPDATE; -- 锁定账户记录,并设置记录锁
-- 执行转账操作,更新账户余额
COMMIT; -- 提交事务

 在执行SELECT balance FROM accounts WHERE account_number = '123456789' FOR UPDATE时,将锁定指定账户记录,并设置记录锁。这样,只有一个用户可以对该账户进行转账操作,其他用户在同一账户上的转账操作会被阻塞。完成转账操作后,使用COMMIT命令提交事务,释放记录锁,允许其他用户继续进行转账操作。

记录锁的底层原理是由MySQL的存储引擎实现的。不同的存储引擎可能会使用不同的方式来管理数据行的锁。一般来说,记录锁是一种行级锁,与其他行级锁(如共享锁、排他锁)相互配合,以实现并发性和数据一致性。

需要注意的是,记录锁用于保证并发事务对数据行的完整性和一致性。在实际使用时,需要根据需求和并发情况合理使用记录锁,以避免死锁和提高性能。

临键锁

Next-Key 可以理解为一种特殊的间隙锁,也可以理解为一种特殊的算法。通过临建锁可以解决幻读的问题。 每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数会锁住一段左开右闭区间的数据。需要强调的一点是,innoDB 中行级锁是据行的临键锁时,基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列) 上不存在临键锁。

你可能感兴趣的:(mysql,mysql,数据库)