sql事务核心是acid:原子性靠undo log,一致性靠应用与约束协同,隔离性靠mvcc+行锁,持久性靠redo log;四大隔离级别对应不同锁策略与并发问题;死锁由循环等待引发,需通过固定顺序、缩短事务等规避。

SQL事务是数据库面试中的高频考点,核心围绕ACID特性、事务隔离级别、锁机制、死锁处理
事务的ACID如何保证?
面试常问“MySQL怎么实现原子性和持久性?”——本质是靠日志和锁协同完成:
- 原子性:通过undo log实现。事务回滚时,用undo log反向执行逻辑(如INSERT变DELETE),确保操作要么全做,要么全不做
- 一致性:由应用层+约束+触发器+事务共同保障,数据库本身不直接实现,但通过隔离级别和锁减少不一致风险
- 隔离性:依赖MVCC(多版本并发控制)+行级锁。读操作尽量走快照读(不加锁),写操作加record lock或gap lock
- 持久性:靠redo log。事务提交前先写redo log(顺序IO),崩溃后通过redo log重放已提交事务
四大隔离级别与典型问题
重点不是背定义,而是理解“每个级别到底锁了什么、能避免哪些现象”:
- Read Uncommitted:不加读锁,可读未提交数据 → 允许脏读、不可重复读、幻读
- Read Committed(RC):每次SELECT都生成新快照,只锁被修改的行 → 解决脏读,但不可重复读和幻读仍存在(InnoDB下普通SELECT不加锁)
- Repeatable Read(RR):事务内第一次SELECT生成快照,后续复用;配合next-key lock(行锁+间隙锁)→ 解决脏读、不可重复读;默认解决大部分幻读(但“当前读”如SELECT ... FOR UPDATE仍可能遇到)
- Serializable:所有读操作加共享锁,写加排他锁 → 完全串行化,解决全部问题,但并发性能最差
锁类型与加锁时机
MySQL InnoDB中锁不是“语句一执行就加”,而取决于隔离级别 + SQL类型 + 索引是否命中:
- 无索引或索引失效时,UPDATE/DELETE会升级为表锁(全表扫描逐行判断)
- 主键等值查询 → 加record lock(单行记录锁)
- 主键范围查询(如WHERE id > 5)→ 加next-key lock(左开右闭区间,含间隙锁)
- 唯一索引等值查询且记录存在 → record lock;记录不存在 → 该位置的gap lock(防插入)
- SELECT ... FOR UPDATE / LOCK IN SHARE MODE → 当前读,必定加锁;普通SELECT在RR下是快照读,不加锁
死锁原理与排查思路
死锁不是故障,而是并发下的正常现象。关键要说明“为什么发生”和“怎么定位”:
- 四个必要条件:互斥、持有并等待、不可剥夺、循环等待。InnoDB主动检测(wait-for graph),自动回滚其中一个事务(通常选undo log小的)
- 常见诱因:多个事务以不同顺序访问相同资源(如事务A先更新user再更新order,事务B反之);间隙锁重叠导致隐式锁冲突
- 排查命令:SHOW ENGINE INNODB STATUS\G 查看最近死锁详情;开启innodb_print_all_deadlocks=ON 记录所有死锁到error log
- 规避建议:固定SQL执行顺序、缩短事务时间、避免大事务、减少非必要索引、用乐观锁替代长事务悲观锁










