锁
锁的类型

全局锁
全局锁就是对整个数据库实例进行加锁,当执行全局锁定操作时,整个数据库将会处于只读状态,所有写操作都会被阻塞,直到全局锁被释放。
在进行全库备份,或者数据迁移时,可以使用全局锁来保证数据的一致性。
在 MySQL 中,可以使用 FLUSH TABLES WITH READ LOCK 命令来获取全局锁。
执行该命令后,所有表将被锁定为只读状态。记得在完成备份或迁移后,使用 UNLOCK TABLES 命令释放全局锁。
表锁了解吗
了解。
表锁常见于 MyISAM 引擎,InnoDB 也可以手动通过 LOCK TABLES 加锁。
适合读多写少、全表扫描或者表结构变更的场景用。
表锁又可以细分为共享锁和排他锁。共享锁允许多个事务同时读表,但不允许写操作。
排他锁只允许一个事务进行写操作,其他事务不能读也不能写。
MyISAM 在执行 SELECT 时会自动加读锁,执行 INSERT/UPDATE/DELETE 时会加写锁。
对于 InnoDB 引擎,无索引的 UPDATE/DELETE 可能会导致锁升级为表锁。
说说 MySQL 的行锁?
行锁是 InnoDB 存储引擎中最细粒度的锁,它锁定表中的一行记录,允许其他事务访问表中的其他行。
底层是通过给索引加锁实现的,这就意味着只有通过索引条件检索数据时,InnoDB 才能使用行级锁,否则会退化为表锁。
行锁又可以细分为记录锁、间隙锁和临键锁三种形式。通过 SELECT ... FOR UPDATE 可以加排他锁。
通过 SELECT ...LOCK IN SHARE MODE 可以加共享锁。
select for update 有什么需要注意的?
第一,必须在事务中使用,否则锁会立即释放。
第二,使用时必须注意是否命中索引,否则可能锁全表。
说说记录锁吧?
记录锁是行锁最基本的表现形式,当我们使用唯一索引或者主键索引进行等值查询时,MySQL 会为该记录自动添加排他锁,禁止其他事务读取或者修改锁定记录。
间隙锁了解吗?
间隙锁用于在范围查询时锁定记录之间的“间隙”,防止其他事务在该范围内插入新记录。仅在可重复读及以上的隔离级别下生效,主要用于防止幻读。
执行什么命令会加上间隙锁?
在可重复读隔离级别下,执行 FOR UPDATE / LOCK IN SHARE MODE 等加锁语句,且查询条件是范围查询时,就会自动加上间隙锁。
临键锁了解吗?
临键锁是记录锁和间隙锁的结合体,锁住的是索引记录和索引记录之间的间隙。
和间隙锁不同,临键锁的间隙是一个左开右闭区间。例如 (1,3] 表示锁定大于 1 且小于等于 3 的所有记录。
当 InnoDB 执行一个范围查询时,会使用临键锁来锁定满足条件的行数据以及该范围内的间隙。
MySQL 默认的行锁类型就是临键锁。当使用唯一索引的等值查询匹配到一条记录时,临键锁会退化成记录锁;如果没有匹配到任何记录,会退化成间隙锁。
意向锁是什么知道吗?
意向锁是一种表级锁,表示事务打算对表中的某些行数据加锁,但不会直接锁定数据行本身。
由 InnoDB 自动管理,当事务需要添加行锁时,会先在表上添加意向锁。这样当要添加表锁的时候,可以通过查看表上的意向锁,快速判断是否有冲突,而无需逐行检查,从而提高加锁效率。
当执行 SELECT ... LOCK IN SHARE MODE 时,会自动加意向共享锁;当执行 SELECT ... FOR UPDATE 时,会自动加意向排他锁。
意向锁之间互相兼容,也不会与行锁冲突。
意向锁的意义是什么?
在没有意向锁的情况下,当事务 A 持有某表的行锁时,如果事务 B 想添加表锁,InnoDB 必须检查表中每一行数据是否被加锁,这种全表扫描的方式效率极低。
有了意向锁之后,事务在加行锁前,先在表上加对应的意向锁;其他事务加表锁时,只需检查表上的意向锁,无需逐行检查。
MySQL的乐观锁和悲观锁了解吗?
悲观锁是一种"先上锁再操作"的保守策略,它假设数据被外界访问时必然会产生冲突,因此在数据处理过程中全程加锁,保证同一时间只有一个线程可以访问数据。MySQL 中的行锁和表锁都是悲观锁。
乐观锁会假设并发操作不会总发生冲突,属于小概率事件,因此不会在读取数据时加锁,而是在提交更新时才检查数据是否被其他事务修改过。
乐观锁并不是 MySQL 内置的锁机制,而是通过程序逻辑实现的,常见的实现方式有版本号机制和时间戳机制。通过在表中增加 version 字段或者 timestamp 字段来实现。
如何通过悲观锁和乐观锁解决库存超卖问题?
悲观锁通过 SELECT ... FOR UPDATE 在查询时直接锁定记录,确保其他事务必须等待当前事务完成才能操作该行数据。
乐观锁通过在表中增加 version 字段作为判断条件。
遇到过MySQL死锁问题吗,你是如何解决的?
遇到过。MySQL 的死锁是由于多个事务持有资源并相互等待引起的。我通过 SHOW ENGINE INNODB STATUS 查看死锁信息,定位到是加锁顺序不一致导致的,最后通过调整加锁顺序解决了这个问题。
