SQL数据库并发控制_锁与MVCC工作机制

11次阅读

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

SQL数据库并发控制_锁与MVCC工作机制

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:它强制当前读+加锁,在高并发更新场景易成瓶颈,优先考虑乐观锁或应用层重试
text=ZqhQzanResources