SQL数据库并发控制由锁机制与MVCC协同实现:锁保障写安全(如X锁防并发修改),MVCC提升读性能(通过版本链与Read View实现快照读);二者分工为“读不阻塞读/写,写阻塞写/部分读”。

SQL数据库的并发控制主要靠锁机制和多版本并发控制(MVCC)协同实现,二者解决的核心问题是:多个事务同时读写同一数据时,如何保证一致性、隔离性,又不严重牺牲性能。
锁机制:显式阻塞,保障写操作安全
锁是数据库最基础的并发控制手段,按粒度分为行锁、页锁、表锁;按功能分为共享锁(S锁,用于读)、排他锁(X锁,用于写)。事务在修改数据前必须先获得对应行的X锁,其他事务若想读或写该行,就得等待锁释放——这就是“阻塞式”控制。
- 读已提交(RC)级别下,SELECT不加锁(快照读),但UPDATE/DELETE会加行级X锁,并在语句执行完立即释放
- 可重复读(RR)级别下,SELECT可能触发间隙锁(Gap Lock)或临键锁(Next-Key Lock),防止幻读;X锁则持续到事务结束
- 死锁不可避免,数据库通过超时检测或等待图分析自动回滚其中一个事务
MVCC:隐式多版本,提升读性能与并发度
MVCC不依赖锁来处理读请求,而是为每一行数据维护多个历史版本,每个事务根据自己的“快照时间点”看到对应的一致性视图。InnoDB中通过隐藏字段DB_TRX_ID(最近修改事务ID)和DB_ROLL_PTR(指向undo日志的指针)实现版本链管理。
- 事务开启时获取一个唯一的、递增的read view,其中包含活跃事务ID列表和最小未提交事务ID
- 查询时遍历版本链,跳过对当前事务不可见的版本(如被更晚事务修改、或属于未提交事务)
- INSERT生成新版本,DELETE标记删除版本,UPDATE实际是INSERT+DELETE组合,旧版本保留在undo log中供回滚或快照读使用
锁与MVCC如何配合工作
它们不是互斥方案,而是分工协作:MVCC负责“读不阻塞读、读不阻塞写”,锁机制负责“写阻塞写、写阻塞部分读”。例如在RR隔离级别下:
- 普通SELECT走MVCC快照读,无需加锁,不会被UPDATE阻塞
- SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE 则走当前读,会加锁并触发最新版本可见性判断
- UPDATE先用MVCC定位要修改的行版本,再加X锁,确保修改期间无人并发更改
实际开发中需注意的关键点
理解底层机制有助于写出高并发友好的SQL:
- 避免长事务:MVCC依赖undo log保留旧版本,长事务导致大量版本堆积、空间膨胀,还可能拖慢purge线程
- 合理选择隔离级别:RC适合读多写少、允许“不可重复读”的场景;RR能防幻读但锁范围更大,可能引发更多锁等待
- WHERE条件务必命中索引:否则行锁会退化为表锁或锁住全表索引范围,极大降低并发能力
- 慎用SELECT ... FOR UPDATE:它强制当前读+加锁,在高并发更新场景易成瓶颈,优先考虑乐观锁或应用层重试










