2571 字
13 分钟

数据库并发控制:原理、问题与解决方案

在数据库系统中,多个用户或应用程序同时访问和修改数据是常态。并发控制作为数据库管理系统(DBMS)的核心功能之一,负责协调多事务的并行执行,确保事务的隔离性(ACID 特性之一)和数据库的一致性。本文将从并发执行方式、潜在问题、控制机制三个维度,系统梳理并发控制的核心知识点。

一、多事务执行方式#

事务的并发执行本质是“如何调度多个事务的操作顺序”,核心目标是在提高系统吞吐量的同时,避免数据不一致。常见的执行方式分为三类:

(1) 事务串行执行#

  • 定义:同一时刻仅允许一个事务执行,其他事务需等待当前事务提交或回滚后才能启动。
  • 特点
    • 优点:天然保证数据一致性,无需复杂控制机制;
    • 缺点:完全浪费系统并行处理能力,在多用户场景下响应速度极慢(例如:100个事务需依次执行,总耗时为单个事务耗时之和)。
  • 适用场景:单用户系统、事务执行时间极短的场景。

(2) 交叉并发方式(Interleaved Concurrency)#

  • 定义:多个事务的操作“轮流交叉”执行(例如:事务1执行操作A → 事务2执行操作B → 事务1执行操作C),本质是“逻辑并行、物理串行”。
  • 特点
    • 优点:单处理机系统的主流并发方式,能充分利用CPU空闲时间(如事务1等待IO时,事务2可执行),提升系统吞吐量;
    • 缺点:需通过调度算法(如两段锁协议)避免数据不一致,否则可能出现丢失修改、脏读等问题。
  • 核心逻辑:通过“时间片轮转”或“优先级调度”实现事务操作的交叉执行,模拟并行效果。

(3) 同时并发方式(Simultaneous Concurrency)#

  • 定义:多处理机系统中,多个事务在不同处理机上同时执行,是“真正的物理并行”。
  • 特点
    • 优点:理论上吞吐量最高,能充分发挥硬件多核性能;
    • 缺点:依赖多处理机硬件环境,且需解决跨处理机的数据同步问题(如分布式锁),实现复杂度极高。
  • 适用场景:大型分布式数据库系统(如MySQL集群、PostgreSQL集群)。

二、事务并发执行带来的问题#

当多个事务并行操作同一批数据时,若缺乏有效的控制机制,会破坏事务的隔离性,导致数据库一致性受损。这是DBMS必须解决的核心问题,也是并发控制机制的设计初衷。

具体来说,并发执行可能引发三类典型的数据不一致问题:

1. 丢失修改(Lost Update)#

  • 场景:两个事务同时读取同一数据并修改,后提交的事务会覆盖先提交事务的修改结果。
  • 示例
    • 事务1:读取余额=100 → 扣除50 → 准备提交(余额=50);
    • 事务2:读取余额=100 → 扣除30 → 先提交(余额=70);
    • 最终结果:事务1提交后余额=50,事务2的修改被丢失(原本应扣除80,余额=20)。
  • 本质:两个事务的写操作相互覆盖,未考虑彼此的修改。

2. 不可重复读(Non-Repeatable Read)#

  • 场景:同一事务内多次读取同一数据,期间其他事务修改并提交了该数据,导致前后读取结果不一致。
  • 示例
    • 事务1:第一次读取商品库存=10 → 执行业务逻辑(如生成订单);
    • 事务2:修改库存=8 → 提交;
    • 事务1:第二次读取库存=8,与第一次结果不一致,导致业务逻辑异常。
  • 注意:不可重复读强调“同一事务内的读取一致性”,区别于“幻读”(幻读是读取范围数据时,其他事务插入/删除数据导致结果集行数变化)。

3. 读“脏”数据(Dirty Read)#

  • 场景:一个事务读取了另一个事务未提交的修改数据,若后续该事务回滚,读取到的数据就是无效的“脏数据”。
  • 示例
    • 事务1:修改余额=200(未提交);
    • 事务2:读取余额=200(基于事务1的未提交修改);
    • 事务1:因业务异常回滚,余额恢复为100;
    • 事务2:基于错误的“脏数据”(200)执行后续操作,导致数据不一致。
  • 本质:读取了未提交的中间数据,违反了“提交读”原则。

三、并发控制机制的核心任务#

并发控制机制的核心目标是“在保证事务隔离性的前提下,最大化系统并发性能”,具体需完成三项任务:

  1. 对多事务的并发操作进行正确调度(如按封锁协议、时间戳顺序调度);
  2. 保证事务的隔离性(避免上述三类数据不一致问题);
  3. 最终维护数据库的一致性(符合业务规则的状态)。

其中,封锁技术是DBMS中应用最广泛的并发控制机制(如MySQL、PostgreSQL均采用),下文将重点详解。

四、封锁技术:并发控制的核心实现#

1. 什么是封锁?#

封锁是事务在操作数据对象(表、行、索引等)前,向DBMS发出的“锁定请求”。加锁后,事务获得该数据对象的特定访问权限,其他事务需等待锁释放后才能操作同一对象。

  • 核心作用:通过“互斥访问”避免并发冲突,是实现事务隔离性的基础。
  • 锁的粒度:支持不同层级的锁定(表锁、行锁、页锁),粒度越细(如行锁),并发性能越高,但锁管理开销越大;粒度越粗(如表锁),并发性能越低,但管理简单。

2. 基本封锁类型#

DBMS提供两种核心封锁类型,通过组合使用实现不同的隔离级别:

封锁类型别称核心权限其他事务权限适用场景
排它锁(X锁)写锁允许事务读取+修改数据不能加任何锁(X/S锁均被禁止)数据修改操作(INSERT/UPDATE/DELETE)
共享锁(S锁)读锁允许事务读取数据只能加S锁(不能加X锁)数据查询操作(SELECT)

3. 基本锁的相容矩阵#

锁的相容性指“一个事务持有某数据的锁后,其他事务能否对该数据加其他类型的锁”,相容矩阵如下(√=允许,×=禁止):

当前锁\请求锁共享锁(S)排它锁(X)
无锁
共享锁(S)×
排它锁(X)××
  • 关键结论:
    • 多个事务可同时持有S锁(读-读不冲突);
    • 任何事务持有X锁时,其他事务无法加锁(写-读、写-写均冲突)。

4. 封锁协议:从“锁”到“隔离性”的规则#

封锁协议是“如何加锁、何时释放锁”的规则集合,不同协议对应不同的隔离级别,解决的问题也不同:

封锁协议核心规则解决的问题未解决的问题对应隔离级别
1级封锁协议事务修改数据前加X锁,事务结束(提交/回滚)后释放丢失修改不可重复读、脏读读未提交(Read Uncommitted)
2级封锁协议1级协议 + 事务读取数据前加S锁,读完后立即释放丢失修改、脏读不可重复读读已提交(Read Committed)
3级封锁协议1级协议 + 事务读取数据前加S锁,事务结束后释放丢失修改、脏读、不可重复读无(理论上)可重复读(Repeatable Read)
  • 补充说明:
    • 3级封锁协议是实现“可重复读”的核心(如MySQL InnoDB的默认隔离级别就是可重复读,基于行锁+MVCC实现);
    • 若需解决“幻读”,需在3级协议基础上增加“间隙锁(Gap Lock)”,实现“串行化(Serializable)”隔离级别。

5. 三级协议的核心区别#

  • 释放S锁的时机:2级协议“读完即释”,3级协议“事务结束才释”——这是解决“不可重复读”的关键;
  • 锁的粒度:协议本身不限制锁粒度,实际应用中结合行锁/表锁,平衡并发性能和管理开销(如InnoDB用行锁实现细粒度控制)。

五、补充:其他并发控制机制(简要介绍)#

除了封锁技术,DBMS还支持其他并发控制方式,适用于不同场景:

  1. 时间戳协议:给每个事务分配唯一时间戳,按时间戳顺序调度事务操作,避免锁竞争(适用于读多写少场景);
  2. 乐观并发控制(OCC):假设事务并发冲突概率低,事务执行时不锁数据,提交前检查是否有冲突,有冲突则回滚重试(适用于高并发读场景,如Redis、MongoDB);
  3. 多版本并发控制(MVCC):为数据维护多个版本,事务读取历史版本,修改操作生成新版本,避免读-写冲突(InnoDB的核心机制,兼顾并发性能和隔离性)。

六、总结#

并发控制的本质是“在并行与一致之间找平衡”:

  • 串行执行保证一致,但牺牲性能;
  • 并发执行提升性能,但需通过封锁、时间戳等机制避免冲突;
  • 封锁协议是最经典的解决方案,3级封锁协议可覆盖大部分业务场景,而MVCC等机制则在高并发场景下提供更优的性能。

对于开发者而言,理解并发控制原理有助于:

  1. 合理设置事务隔离级别(如敏感业务用可重复读,普通查询用读已提交);
  2. 避免长事务导致的锁等待/死锁;
  3. 优化高并发场景下的数据库性能(如减少锁粒度、使用乐观锁)。
数据库并发控制:原理、问题与解决方案
https://firefly.cuteleaf.cn/posts/concurrency-control/
作者
Becorer
发布于
2025-12-14
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-12-14

目录