MySQL中有几种类型的锁?
锁粒度来分,有表锁、页锁和行锁。
加锁机制划分,有乐观锁和悲观锁。
按兼容性划分,有共享锁和排他锁。
按锁模式划分,有记录锁,间隙锁,next-key锁,意向锁、插入意向锁
全局锁了解吗?
全局锁是对整个数据库实例加读锁,整个数据库处于只读状态,所有写操作被阻塞,直到全局锁被释放。
使用场景是全库备份,或者数据迁移时,使用全局锁来保证数据的一致性。
-- 锁定整个数据库
FLUSH TABLES WITH READ LOCK;-- 执行备份操作
-- 例如使用 mysqldump 进行备份
! mysqldump -u username -p database_name > backup.sql-- 释放全局锁定
UNLOCK TABLES;
表锁了解吗?
常见于MyISAM引擎,InnoDB可以通过LOCK TABLES加锁
适合读多写少,全表扫描和表结构变更时使用。
表锁也分为共享锁(读锁),排他锁(写锁)。
MyISAM在指向SELECT操作时会自动加读锁,UPDATE/DELETE/INSERT的时候会自动加写锁
对于 InnoDB 引擎,无索引的 UPDATE/DELETE
只能先进行全表扫描,可能会导致锁大量行被锁定,类似于表锁。
ALTER TABLE会加排它锁
说说MySQL的行锁?
InnoDB中最细粒度的锁,锁定表中的一行记录,允许其他事务访问表中的其他行。
有索引的情况下,通过索引只锁满足条件的行;无索引的情况下,全表遍历,遍历一行就加一行行锁,最差的情况会锁定所有行,直到事务完成才会释放所有行锁。
行锁又可以细分为记录锁,间隙锁和临键锁。
通过SELECT .... FOR UPDATE可以加排它锁。
通过SELECT .... IN SHARE MODE可以加共享锁。
select for update有什么需要注意的?
- 必须在事务中使用,否则锁会立即释放。
- 使用时注意是否命中索引,否则可能会锁大量行。
说说记录锁
记录锁是行锁的最基本的表现形式,当我们使用唯一索引或者主键索引进行等值查询并显式指定FOR UPDATE的时候,MySQL会为该行添加排它锁类型的记录锁,禁止其他行读取或修改记录。
注意使用非主键索引进行UPDATE时的锁定路径:辅助索引 → 主键索引
间隙锁了解吗?
范围查询或者不存在的记录查询时,用于锁定记录之间的间隙,防止其他事务在范围中插入新纪录,在可重复读的事务隔离级别下生效,主要为了防止幻读现象。
临键锁了解吗?
临键锁就是间隙锁+记录锁,锁住记录以及记录之前的间隙,左开右闭,范围查询时生效。
当使用唯一索引的等值查询匹配到一条记录时,临键锁会退化成记录锁;如果没有匹配到任何记录,会退化成间隙锁。
意向锁是什么?
意向锁是一种表级锁,表示事务打算对表中的某些行数据加锁,但是不会先直接锁定行数据本身。
由InnoDB自动管理,当事务需要添加行锁时,会先在表上添加意向锁。这样当另一个事务要添加表锁的时候,可以通过查看表上的意向锁,快速判断表级锁与现有行锁的冲突,避免逐行扫描。
当执行SELECT .... LOCK IN SHARE MODE的时候,会自动添加意向共享锁;当执行 SELECT .... FOR UPDATE的时候,会自动添加意向排他锁。
意向锁之间相互兼容,也不会和行锁冲突。
当前锁 | IS | IX | S(表级) | X(表级) |
---|---|---|---|---|
IS | ✅ | ✅ | ✅ | ❌ |
IX | ✅ | ✅ | ❌ | ❌ |
S(表级) | ✅ | ❌ | ✅ | ❌ |
X(表级) | ❌ | ❌ | ❌ | ❌ |
MySQL的乐观锁和悲观锁了解吗?
悲观锁是一种"先上锁再操作"的保守策略,它假设数据被外界访问时必然会产生冲突,因此在数据处理过程中全程加锁,保证同一时间只有一个线程可以访问数据。MySQL 中的行锁和表锁都是悲观锁。
乐观锁会假设并发操作不会总发生冲突,属于小概率事件,因此不会在读取数据时加锁,而是在提交更新时才检查数据是否被其他事务修改过。常见的实现方式有版本号机制和时间戳机制。通过在表中增加 version 字段或者 timestamp 字段来实现。
如何通过乐观锁和悲观锁解决库存超卖的问题?
悲观锁通过 SELECT ... FOR UPDATE
在查询时直接锁定记录,确保其他事务必须等待当前事务完成才能操作该行数据。
乐观锁通过在表中增加 version 字段作为判断条件。
有遇到过MySQL的死锁问题吗?是如何解决的?
MySQL的死锁问题是多个事务同时持有资源并且相互等待对方的资源释放引起的。访问相同的资源,但顺序不同,就会导致死锁。我用SHOW ENGINE INNODB STATUS查看死锁信息,发现是加锁顺序不一致导致的死锁问题,调整加锁顺序之后恢复正常。