MySQL面试题-锁

MySQL面试题-锁
最新回答
泪濡湿了梦

2026-10-29 15:48:32

MySQL面试题-锁

1. 对MySQL的锁了解吗?

MySQL的锁机制是为了保证在并发事务环境下数据的一致性和完整性。当多个事务同时访问同一数据时,可能会产生数据不一致的问题,锁机制通过控制访问的次序来解决这一问题。锁就像酒店房间的钥匙,只有持有钥匙的人才能进入房间,其他人需要等待。

2. 隔离级别与锁的关系

  • Read Uncommitted(未提交读):读取数据不需要加共享锁,不会与被修改数据上的排他锁冲突,但可能读取到未提交的数据,即“脏读”。
  • Read Committed(提交读):读操作需要加共享锁,但在语句执行完后释放,只能读取到已提交的数据,避免了脏读,但可能出现“不可重复读”。
  • Repeatable Read(可重复读):读操作需要加共享锁,在事务提交前不释放,保证了在同一事务中多次读取同一数据的结果一致,避免了不可重复读,但可能出现“幻读”。
  • SERIALIZABLE(可串行化):限制性最强的隔离级别,锁定整个范围的键并一直持有锁直到事务完成,避免了所有并发问题,但性能开销最大。

3. 按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法

  • 行级锁(row-level locking):粒度最细,只针对当前操作的行加锁,能大大减少数据库操作的冲突,但加锁开销大,可能出现死锁。InnoDB引擎默认使用行级锁。
  • 表级锁(table-level locking):粒度最大,对当前操作的整张表加锁,实现简单,资源消耗少,但并发度低,冲突多。MyISAM引擎使用表级锁。
  • 页级锁(page-level locking):粒度介于行级锁和表级锁之间,一次锁定相邻的一组记录,开销和加锁时间也介于两者之间。BDB引擎使用页级锁。

4. 从锁的类别上分MySQL都有哪些锁?

  • 共享锁(shared lock):又叫做读锁,用于数据的读取操作,允许多个共享锁同时存在,但不允许排他锁存在。
  • 排他锁(exclusive lock):又叫做写锁,用于数据的写入操作,排他锁存在时,不允许其他共享锁和排他锁存在。

锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁、页级锁、表级锁,加锁开销从大到小,并发能力也是从大到小。

5. MySQL中InnoDB引擎的行锁是怎么实现的?

InnoDB是基于索引来完成行锁的。例如,SELECT * FROM tab_with_index WHERE id = 1 FOR UPDATE;这条语句会根据索引键id来完成行锁锁定。如果id不是索引键,InnoDB将完成表锁,并发将无从谈起。

6. InnoDB存储引擎的锁的算法有三种

  • Record lock:单个行记录上的锁。
  • Gap lock:间隙锁,锁定一个范围,不包括记录本身,用于阻止多个事务将记录插入到同一范围内,避免幻读问题。
  • Next-key lock:record+gap,锁定一个范围,包含记录本身,InnoDB对于行的查询默认使用next-key lock。

相关知识点:

  • InnoDB使用next-key lock是为了解决Phantom Problem(幻读问题)。
  • 当查询的索引含有唯一属性时,next-key lock会降级为record lock。
  • 有两种方式显式关闭gap锁:将事务隔离级别设置为Read Committed(RC)或将参数innodb_locks_unsafe_for_binlog设置为1。

7. 什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

常见的解决死锁的方法:

  • 约定以相同的顺序访问表,可以大大降低死锁机会。
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
  • 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。
  • 如果业务处理不好,可以用分布式事务锁或者使用乐观锁。

8. 数据库的乐观锁和悲观锁是什么?怎么实现的?

  • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制。
  • 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:一般会使用版本号机制或CAS算法实现。

两种锁的使用场景:

  • 乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
  • 如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。