面试不会问题
1. 什么是表锁?什么是行锁?什么情况下会使用表锁?
InnoDB引擎通过“索引”实现行锁(锁定满足条件的行),但如果操作无法通过索引定位行,会导致行锁失效,进而升级为表锁。常见的表现为:
(1)条件中未使用索引,InnoDB 无法定位具体行,会锁整个表;
(2)使用非索引列的范围查询,范围查询无法通过索引锁定行,触发表锁;
(3)索引失效(如函数 / 类型转换),索引失效后无法定位行,触发表锁;
(4)更新全表的操作,因需更新所有行,行锁效率低于表锁。
InnoDB 使用表锁的核心场景可分为 “主动使用” 和 “被动退化” 两类,本质是当 “行锁无法高效实现” 或 “表锁成本更低” 时的选择:
(1)主动使用表锁的场景(显式或隐式):场景 1:无索引 / 索引失效导致的全表扫描更新、场景 2:执行 LOCK TABLES
显式锁表、场景 3:DDL 操作(数据定义语言):所有 DDL 操作(如 ALTER TABLE
、DROP TABLE
、CREATE INDEX
等)会自动加 表级排他锁,防止 DDL 过程中表数据被修改导致结构不一致。
(2)被动退化到表锁的场景:这类场景是 InnoDB 尝试加行锁失败后,被迫升级为表锁:场景:行锁冲突过于频繁,触发 “锁升级”:InnoDB 虽然支持行锁,但每个行锁的维护(如锁结构存储、冲突检查)需要消耗内存。当一个事务需要锁定 极多的行(如锁定数万行),且行锁冲突频繁时,MySQL 可能会触发 锁升级(Lock Escalation)—— 将大量行锁合并为一个表锁,减少内存消耗和冲突检查成本。
2. 责任链设计模式?策略模式?模板方法模式?
先明确三者的 “本质定位”—— 不同模式解决的核心问题完全不同:
模板方法模式:解决 “步骤固定但细节可变” 的问题(定义流程骨架,留空细节);
策略模式:解决 “多种算法 / 行为可选” 的问题(封装不同实现,动态切换);
责任链模式:解决 “多个对象依次处理请求” 的问题(请求传递,直到被处理)。
使用场景:
模板方法模式:适合 “流程固定,细节可变” 的场景;
策略模式:适合 “多种算法可选,需动态切换” 的场景;
责任链模式:适合 “请求需多步处理,且处理者不确定” 的场景。
(1)责任链模式
核心是 “将多个处理器(Handler)连成一条链,请求沿着链传递,使用多个节点来处理它”。它的存在主要是为了解决三类核心问题:①解耦 “请求发送者” 与 “请求处理者”:传统写法中,发送者需要知道哪个处理器能处理请求,比如说使用if-else来判断,一旦处理器增减或逻辑变化,发送者代码必须修改。责任链模式中,发送者只需将请求 “丢给链的头部”,无需关心链上有多少处理器、谁来处理 —— 处理器的增减 / 顺序调整,完全不影响发送者。②支持 “动态组合处理流程”:责任链的处理器可以动态添加、删除或调整顺序,灵活适配不同场景。③避免 “if-else/switch” 的代码臃肿:当处理逻辑有多个分支且可能扩展时,if-else
会导致代码冗长、可读性差,责任链用 “对象链” 替代分支判断,代码更符合单一职责原则(每个处理器只处理自己负责的逻辑)。
(2)模板方法模式
核心定义:定义一个固定的流程骨架(父类),将流程中 “可变的步骤” 延迟到子类实现,确保流程的一致性,同时允许细节灵活调整。
核心思想:“骨架不可变,细节可变”,是一种 “父类定规矩,子类填内容” 的模式。
(3)策略模式
核心定义:将多种可替换的算法 / 行为封装成独立的 “策略类”,使算法与使用算法的 “上下文” 解耦,上下文可动态切换不同策略(无需修改原有代码)。
核心思想:“算法家族化,切换动态化”,是一种 “选择不同实现” 的模式。
3. MySQL中有哪些事务隔离级别?
读未提交、读已提交、可重复读、串行化。
(1)读已提交如何解决脏读?
脏读:一个事务读取到另一个事务未提交的修改(可能被回滚的数据)。
RC 级别通过 **“只读取已提交的数据”** 解决脏读,核心机制是:
每次读取都获取最新的已提交版本:事务中每次执行
SELECT
时,都会去读取其他事务已经提交的数据版本,忽略未提交的修改。实现方式:依赖 MySQL 的多版本并发控制(MVCC)。每个事务修改数据时,会生成一个新的数据版本,并标记版本号(与事务 ID 关联)。RC 级别下,查询只会看到 “版本号小于当前事务 ID 且已提交” 的数据,因此不会读取到未提交的脏数据。
(2)可重复读如何解决脏读和不可重复读?
1. 解决脏读的机制:与 读已提交 级别类似,可重复读 也通过 MVCC 保证 “只读取已提交的数据”,但对 “已提交版本” 的判断更严格:
事务启动时会生成一个一致性快照(基于当时的全局事务 ID),整个事务内的所有
SELECT
都读取这个快照中的数据。快照中只包含 “在事务启动前已提交的版本”,完全忽略事务启动后其他事务的未提交修改,因此不会出现脏读。
2. 解决不可重复读的机制:可重复读 通过 **“事务内读取一致性快照”** 解决不可重复读:
事务启动时生成的快照会被整个事务复用,无论其他事务是否提交新的修改,本事务内的
SELECT
始终读取快照中的旧版本,确保多次读取结果一致。
(3)可重复读如何解决幻读?
幻读:同一事务内两次范围查询,结果因其他事务插入新数据而增多(“幻觉” 出新行)。
MySQL 的 InnoDB 引擎在 可重复读 级别通过 **“MVCC 快照读 + 间隙锁当前读”** 组合解决幻读:
快照读(普通
SELECT
):
依赖一致性快照,事务内两次范围查询都读取快照数据,其他事务插入的新数据不在快照中,因此不会看到 “新增的行”。当前读(加锁查询 / 写操作,如
SELECT ... FOR UPDATE
、INSERT
):
通过间隙锁(Gap Lock) 锁定 “可能插入新数据的区间”,阻止其他事务在该区间插入数据,从源头避免新行产生。