MySQL锁整体介绍

常见的 MySQL 锁类型

MySQL 中有多种类型的锁,用于管理并发访问数据库时的数据一致性和并发控制。以下是:

  • 共享锁(Shared Lock):也称为读锁。多个事务可以同时持有共享锁,并同时读取被锁定的数据,但不能进行写操作。共享锁之间不会互相阻塞,因此多个事务可以并发地持有共享锁。
  • 排他锁(Exclusive Lock):也称为写锁。只有一个事务可以持有排他锁,并且在持有排他锁期间可以进行读取和写入操作。其他事务无法同时持有排他锁或共享锁,避免了并发写入冲突。
  • 记录锁(Record Lock):也称为行级锁。在事务中,对特定行进行操作时可以使用记录锁。记录锁可以是共享的或排他的,用于保护事务在对行进行读取或写入时的一致性。
  • 间隙锁(Gap Lock):用于保护事务在范围查询时的一致性。间隙锁锁定了一个范围的键值之间的间隙,防止其他事务在该范围内插入新记录。间隙锁可以防止幻读(Phantom Read)的问题。
  • 临键锁(Next-Key Lock):结合了记录锁和间隙锁的特性,用于保护事务在范围查询时的一致性。临键锁不仅锁定了记录,还锁定了记录之前的间隙,确保事务在读取范围内的数据时不会受到其他事务的干扰。
  • 表锁(Table Lock):最粗粒度的锁,锁定整个表。在持有表锁的事务执行期间,其他事务无法对该表进行读取或写入操作。表锁对并发性能有较大影响,一般情况下应尽量避免使用。
    这些锁类型在 MySQL 中用于实现并发控制和数据一致性。根据具体的应用场景和需求,可以选择适当的锁类型来管理并发访问数据库时的资源竞争。同时,MySQL 还提供了锁机制的配置选项,例如隔离级别(Isolation Level)和锁超时时间(Lock Timeout),以便根据具体需求进行调整。
    注意上面的划分不是统一维度。
    共享锁和排他锁是按照不同事务读写数据的权限来划分。具体锁住的内容都是记录本身,也就是记录锁;
    记录锁、间隙锁、临键锁、表锁是按照锁的数据范围来划分。范围越大,性能越差。

共享锁

Q1:共享锁锁的是table还是record
A1:在 MySQL 中,共享锁(Shared Lock)是用于锁定记录(row)级别的锁,而不是整个表(table)级别的锁。
当使用共享锁时,多个事务可以同时持有共享锁,并且可以并发地读取表中的记录。共享锁允许并发读取,但不允许并发写入。这意味着其他事务可以同时获取共享锁,并读取被锁定记录的内容,但在有事务持有共享锁期间,其他事务无法获得排他锁或进行写入操作。
需要注意的是,共享锁只能防止其他事务获取排他锁,以及防止其他事务修改被锁定的记录。如果其他事务也只是要获取共享锁,则可以同时获取共享锁,并且可以并发地读取相同的记录。
因此,在使用共享锁时,锁的粒度是记录级别,而不是整个表级别。每个记录可以独立地被锁定或解锁,以实现并发访问控制和数据一致性。
使用demo
SELECT * FROM user_tab WHERE user = 'sam' LOCK IN SHARE MODE;
上述语句使用了 LOCK IN SHARE MODE 子句,它会在查询期间获取共享锁。共享锁允许其他事务同时持有共享锁,并且可以读取被锁定的记录,但不能修改。
使用共享锁的目的是允许多个事务同时读取被锁定的记录,以提高并发性。共享锁不会阻塞其他事务的读取操作,但会阻塞持有排他锁的事务的写入操作。
请注意,共享锁的使用也需要考虑事务的隔离级别(Isolation Level)以及锁的范围和持续时间等因素,以确保并发访问时的数据一致性和性能。

排他锁

Q2:排他锁锁的是table还是record
A2:在 MySQL 中,排他锁(Exclusive Lock)是用于锁定记录(row)级别的锁,而不是整个表(table)级别的锁。
当使用排他锁时,只有一个事务可以持有排他锁,并且其他事务无法同时持有排他锁或共享锁。排他锁可以防止其他事务同时读取或修改被锁定的记录,确保在持有排他锁的事务执行期间,其他事务无法对被锁定的记录进行读取或写入操作。
因此,排他锁的粒度是记录级别,而不是整个表级别。每个记录可以独立地被锁定或解锁,以实现并发访问控制和数据一致性。
需要注意的是,使用排他锁可能会导致并发性降低,因为其他事务需要等待持有排他锁的事务释放锁才能继续操作。因此,在使用排他锁时,需要权衡数据一致性和并发性之间的关系,并根据具体的业务需求进行调整。
请注意,上述描述是针对记录级别的排他锁。在某些情况下,也可以使用表级别的排他锁,但这需要特殊的锁机制和语法。一般情况下,推荐使用记录级别的锁来实现更细粒度的并发控制。
使用demo
要更新 user_tab 表中 user 等于 "sam" 的记录的 email 字段为 "hello@shopee.com" 并使用排他锁,可以使用以下 SQL 语句:
BEGIN; SELECT * FROM user_tab WHERE user = 'sam' FOR UPDATE; UPDATE user_tab SET email = 'hello@shopee.com' WHERE user = 'sam'; COMMIT;
上述语句使用了 FOR UPDATE 子句,在查询期间获取排他锁。排他锁会阻塞其他事务对被锁定记录的读取和写入操作,确保在当前事务完成更新操作之前,其他事务无法同时修改该记录。

下面是一些转载的介绍:
共享锁 (lock in share mode),排他锁 (for update)转自 https://blog.csdn.net/u011547570/article/details/121232774
my39_InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析 https://www.cnblogs.com/perfei/p/11262449.html
MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等) https://blog.csdn.net/mysteryhaohao/article/details/51669741
MySQL死锁问题实例分析及解决方法 https://blog.51cto.com/dbachina/781938

posted @ 2023-05-11 10:06  daniel456  阅读(21)  评论(0编辑  收藏  举报