云计算百科
云计算领域专业知识百科平台

后端并发数据安全:悲观锁与乐观锁原理、对比、扩展锁方案全解析

一、前言

高并发场景下多个请求同时修改同一行数据,若无并发控制机制,会出现数据覆盖、状态错乱、统计数值不准、库存超卖等脏数据问题。 关系型数据库提供两套原生并发控制方案:悲观锁、乐观锁,二者设计思路完全相反,适配不同并发争抢场景。除此之外,嵌入式数据库、分布式集群还有专属锁实现方案,下文一并完整拆解。

并发锁是一类并发控制机制的统称。在多线程、多进程、多服务并发场景下,多个请求同时读写同一份共享数据时,用来协调访问顺序、防止并发修改造成脏数据、数据覆盖、状态错乱的方案。

后端开发中常见实现方案包含:悲观锁、乐观锁、SQLite 操作系统文件锁、Redis 分布式锁。 不同锁底层实现、生效范围、并发能力差异巨大,需要结合部署架构(单机 / 分布式)、业务并发压力选型。

二、悲观锁(强一致性锁)

2.1 核心设计思想

默认并发一定会产生资源冲突,操作数据前先主动锁定目标资源,整个事务全程持有锁,事务提交 / 回滚后才释放;其余请求必须阻塞排队,等待锁释放后才能操作数据。

2.2 核心特点

  • 数据安全性极高,完全杜绝并发修改覆盖问题;
  • 存在线程阻塞、排队等待逻辑,资源争抢激烈时整体并发吞吐大幅下降;
  • 依赖数据库原生行锁、表锁机制实现,仅 MySQL、PostgreSQL 这类服务型数据库支持;
  • 长事务会长期占用锁,极易引发锁等待超时、接口雪崩。
  • 2.3 基础 SQL 示例

    — 开启事务并对目标行加悲观行锁
    BEGIN;
    SELECT * FROM table WHERE id = 1 FOR UPDATE;
    — 执行更新逻辑
    UPDATE table SET num = num – 1 WHERE id = 1;
    COMMIT;

    2.4 适用场景

    高并发写入、资源争抢频率极高、零脏数据容忍的核心流程:库存扣减、资金交易、订单核销、账务结算等业务。

    三、乐观锁(高性能无阻塞锁)

    3.1 核心设计思想

    默认日常并发冲突极少,不提前上锁,直接执行业务查询与更新逻辑;更新操作前通过版本号 version、更新时间戳 update_time 校验当前数据是否被其他请求修改,校验失败则判定冲突,执行放弃或重试逻辑。

    3.2 核心特点

  • 全程无阻塞、无锁等待,系统并发吞吐性能更高;
  • 仅依靠普通字段判断实现,无数据库行锁资源开销;
  • 冲突发生后需要业务层手动编写重试逻辑;极端高频争抢场景会产生大量重试,消耗 CPU 资源。
  • 3.3 通用实现 SQL 模板

    1.建表增加版本字段

    CREATE TABLE demo(
    id INT PRIMARY KEY,
    count INT,
    version INT DEFAULT 0
    );

    2.更新时校验版本

    UPDATE demo
    SET count = count – 1, version = version + 1
    WHERE id = 1 AND version = 1;

    执行后判断受影响行数,等于 0 代表数据已被其他线程修改,触发冲突重试。

    3.4 适用场景

    低并发修改、读多写少业务:基础信息修改、普通表单更新、静态统计数据录入、配置更新等冲突概率极低的场景。

    四、悲观锁 vs 乐观锁完整对比表

    对比维度悲观锁乐观锁
    执行逻辑 先上锁、后操作、事务结束释放锁 先查询操作、更新前校验版本,冲突重试
    并发性能 低,高争抢场景大量请求阻塞排队 高,全程无锁阻塞
    数据安全能力 极高,完全避免并发数据覆盖 较高,依赖版本字段校验兜底
    数据库资源开销 高,长期占用行锁资源 极低,仅普通条件判断
    高频争抢场景适配 适合,无无限重试损耗 不适合,大量冲突重试消耗 CPU
    事务依赖 强依赖事务,锁生命周期绑定事务 不强制依赖完整事务,单条 UPDATE 即可实现

    五、SQLite 专属操作系统文件锁

    前面两种锁均基于服务型数据库行锁,嵌入式 SQLite 无行锁、表锁能力,底层依靠操作系统文件锁实现并发隔离,属于特殊锁机制。

    底层原理 SQLite 数据库为单一磁盘文件,区分两种文件锁:共享锁(读)、排他锁(写)。

    1.读请求:加共享锁,多进程可同时读取;

    写请求:加排他锁,同一时间全局仅允许一个写入操作。

    即使开启 WAL 读写分离优化,也只能做到读写不互斥,写入操作依旧串行执行

    2.致命缺陷

    • 仅支持单机本地文件,NFS、SMB 共享磁盘下文件锁失效,直接造成数据错乱;
    • 多进程高频写入频繁抛出 database is locked 锁超时异常;
    • 锁粒度是整个数据库文件,无法精准锁定单行数据。

    3.通用规避方案 开启 WAL 模式、延长 busy_timeout 锁等待时间、批量合并写入、上层增加写入重试逻辑;多服务共用 SQLite 文件架构不推荐长期使用。

    六、Redis 分布式锁(跨机器集群专用)

    悲观锁、乐观锁、SQLite 文件锁全部仅在单台服务器、单个数据库实例内生效;微服务、多节点分布式架构下,需要全局锁控制并发,此时采用 Redis 分布式锁。

    1.实现核心原理 利用 Redis 单命令原子性抢占锁:SET lock_key unique_id NX EX 30

    • NX:key 不存在时才创建,代表抢占锁成功;
    • EX:设置锁自动过期时间,防止进程崩溃永久死锁;
    • unique_id:客户端唯一标识,避免释放其他线程的锁。

    2.优势与短板

    • 优势:跨服务器、跨服务全局互斥,适配分布式集群高并发场景;
    • 短板:依赖 Redis 服务可用性,需要处理主从切换丢锁、任务未完成锁过期等边界问题。

    3.适用场景 多实例微服务、多服务器部署、定时任务防重复执行、分布式库存扣减等单机锁无法覆盖的场景。

    对比维度悲观锁(MySQL/PG)乐观锁(版本号)SQLite 文件锁Redis 分布式锁
    生效范围 单机数据库实例内 单机数据库实例内 仅限单台本机 ✅ 跨机器、分布式集群
    锁粒度 行级 / 表级 逻辑行级(业务层) 整库文件 自定义业务 Key
    阻塞特性 阻塞等待,争抢会排队 无阻塞,冲突后重试 写操作全局串行阻塞 抢占模式,抢不到可重试
    并发写入上限 较高(行锁互不干扰) 高(冲突依赖重试) 很低,同一时刻只能一个写 高,全局互斥
    依赖组件 MySQL/PostgreSQL 任意关系数据库 SQLite + OS 文件锁 Redis 服务
    典型缺陷 长事务易引发锁等待、死锁 超高并发场景大量重试消耗 CPU 共享盘 (NFS/SMB) 锁失效、频繁database is locked 需要处理锁过期、主从切换丢锁、防误释放
    典型适用场景 单机核心交易、库存、资金业务 读多写少、配置、普通表单更新 单机小型工具、低并发本地存储 微服务、多服务器集群、定时任务防重复

    七、落地选型完整判断标准

  • 单机 MySQL/PostgreSQL、高争抢核心交易、不允许脏数据 → 悲观锁;
  • 单机服务、读多写少、修改频次低 → 乐观锁;
  • 单机嵌入式工具、使用 SQLite 存储数据 → 依靠文件锁 + 重试兜底,不适合高并发写入;
  • 多服务器、微服务分布式集群,单机锁失效 → Redis 分布式锁;
  • 补充建议:SQLite 无行锁能力,长期迭代、多进程项目建议迁移 PostgreSQL,从底层规避锁竞争问题。
  • 八、总结

    并发锁是统称,用来解决多请求同时修改共享资源引发的数据冲突;根据单机、分布式场景,衍生出悲观锁、乐观锁、文件锁、分布式锁多种实现。

  • 悲观锁以牺牲并发性能换取绝对数据安全,是核心资金、库存业务首选;
  • 乐观锁无阻塞、吞吐更高,适合查询为主、极少修改的通用业务;
  • SQLite 文件锁是嵌入式数据库妥协方案,存在天生并发上限,仅适合低流量单机工具;
  • 分布式多节点架构,单机数据库锁完全失效,必须引入 Redis 分布式锁实现全局并发控制;
  • 锁架构选型不能一概而论,需要结合部署架构(单机 / 分布式)、业务修改频次、数据容错要求综合判断,避免前期架构埋坑。
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » 后端并发数据安全:悲观锁与乐观锁原理、对比、扩展锁方案全解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!