news 2026/4/21 23:44:09

完整理解乐观锁!!(以预定系统为例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
完整理解乐观锁!!(以预定系统为例)

乐观锁:并发控制的智慧之道

什么是乐观锁?

乐观锁(Optimistic Locking)是一种并发控制机制,其核心思想是"假设冲突很少发生"。与悲观锁(Pessimistic Locking)不同,悲观锁在访问共享资源前会先加锁,阻止其他线程同时访问;而乐观锁则假设数据在大多数情况下不会发生冲突,因此在读取数据时不加锁,仅在更新数据时检查数据是否被其他线程修改过。

乐观锁的实现原理

乐观锁通常通过版本号(Version Number)或时间戳(Timestamp)来实现:

  1. 版本号机制:为每个数据记录添加一个版本号字段
  2. 读取数据:读取数据时同时读取版本号
  3. 更新数据:更新数据前检查版本号是否发生变化
  4. 验证冲突:如果版本号未变化则更新数据并递增版本号,否则更新失败

核心实现逻辑

sql -- 读取数据 SELECT id, name, version FROM table WHERE id = 1; -- 更新数据(带版本号验证) UPDATE table SET name = 'new_value', version = version + 1 WHERE id = 1 AND version = current_version;

如果UPDATE语句影响的行数为0,说明数据在读取后被其他线程修改过,需要重新获取数据并重试操作。

乐观锁的优势

  1. 高并发性能:读取操作无需加锁,适合读多写少的场景
  2. 减少锁竞争:避免了线程阻塞和上下文切换的开销
  3. 资源消耗低:不占用系统锁资源
  4. 可扩展性好:适合分布式系统

乐观锁的劣势

  1. 冲突重试开销:高并发写入时可能需要多次重试
  2. 不适合高冲突场景:写入频繁时性能可能不如悲观锁
  3. 业务逻辑复杂:需要处理重试逻辑和异常情况

实际应用场景

乐观锁广泛应用于以下场景:

  • 电商系统:库存管理、订单状态更新
  • 银行系统:账户余额更新
  • 内容管理系统:文档编辑、版本控制
  • 酒店预订系统:房间状态更新

乐观锁触发示例:酒店预订系统场景

让我通过一个完整的示例来说明乐观锁是如何在实际场景中被触发的。

场景设定

假设我们有一个酒店预订系统,两个前台工作人员Alice和Bob同时处理同一个预订记录:

  • 预订ID: 1001
  • 当前版本号: 1
  • 预订状态: 待确认

事件时间线

时间点T1 - Alice操作

Alice打开预订记录,准备更新联系人信息:

javascript // Alice读取预订信息 const reservation = await getRoomReservationById(1001); // 返回数据: // { // id: 1001, // contactName: "张三", // phoneNumber: "13800138000", // version: 1, // status: "待确认" // }

时间点T2 - Bob操作

几乎同时,Bob也打开了同一份预订记录:

javascript // Bob读取预订信息 const reservation = await getRoomReservationById(1001); // 返回相同的数据: // { // id: 1001, // contactName: "张三", // phoneNumber: "13800138000", // version: 1, // status: "待确认" // }

时间点T3 - Alice提交更新

Alice首先完成修改并提交:

javascript // Alice尝试更新预订信息 const updateData = { id: 1001, contactName: "张三丰", // 修改联系人姓名 phoneNumber: "13800138000", version: 1, // Alice读取时的版本号 status: "待确认" }; // 发送到后端的更新请求 await updateRoomReservation(updateData);

后端执行SQL:

sql UPDATE room_reservation SET contact_name = '张三丰', version = version + 1 WHERE id = 1001 AND version = 1;

结果: 影响1行记录,更新成功,数据库中版本号变为2。

时间点T4 - Bob提交更新(触发乐观锁)

Bob稍后提交他的修改(更新电话号码):

javascript // Bob尝试更新预订信息 const updateData = { id: 1001, contactName: "张三", // Bob未修改联系人姓名 phoneNumber: "13900139000", // 修改电话号码 version: 1, // Bob读取时的版本号(仍然是1) status: "待确认" }; // 发送到后端的更新请求 await updateRoomReservation(updateData);

后端执行SQL:

sql UPDATE room_reservation SET phone_number = '13900139000', version = version + 1 WHERE id = 1001 AND version = 1; -- 注意:这里的version是1

乐观锁触发!

关键点: 此时数据库中预订ID为1001的记录的版本号已经是2(被Alice的更新操作递增了),但Bob的更新请求仍然使用版本号1作为条件。

执行结果:

  • SQL影响0行记录(因为没有version=1的记录了)
  • 更新失败,触发乐观锁机制
  • 后端返回错误信息

前端处理

javascript try { await updateRoomReservation(updateData); console.log("更新成功"); } catch (error) { if (error.message.includes("乐观锁")) { // 乐观锁冲突处理 alert("检测到数据冲突,请刷新后重试"); // 重新加载最新数据 const latestReservation = await getRoomReservationById(1001); // 提示用户数据已被其他用户修改 console.log("最新数据:", latestReservation); } }

完整的乐观锁处理流程

javascript // 带重试机制的更新函数 async function updateReservationWithRetry(reservationData, maxRetries = 3) { let retries = 0; while (retries < maxRetries) { try { // 尝试更新 await updateRoomReservation(reservationData); console.log("更新成功"); return true; } catch (error) { if (error.message.includes("乐观锁") || error.response?.data?.code === 500) { retries++; if (retries >= maxRetries) { alert("更新失败次数过多,请稍后重试"); return false; } console.log(`乐观锁冲突,第${retries}次重试`); // 重新获取最新数据 const latestData = await getRoomReservationById(reservationData.id); // 合并用户的新修改到最新数据中 reservationData.version = latestData.data.version; // 使用最新版本号 // 这里可能需要合并用户的修改到最新数据中 // 具体实现取决于业务逻辑 console.log(`重试第${retries}次,使用版本号: ${reservationData.version}`); } else { // 非乐观锁错误,直接抛出 throw error; } } } }

总结

乐观锁的触发是并发控制的正常表现:

  1. 触发条件: 多个用户同时修改同一数据记录
  2. 检测机制: 通过版本号验证数据是否被修改
  3. 处理方式: 失败后重试或提示用户
  4. 业务价值: 保证数据一致性,避免脏写

这种机制确保了在高并发场景下数据的完整性,同时避免了传统锁机制可能带来的性能问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 23:36:08

2025最新!专科生必看!8个AI论文平台测评,写毕业论文不再难

2025最新&#xff01;专科生必看&#xff01;8个AI论文平台测评&#xff0c;写毕业论文不再难 2025年专科生论文写作工具测评&#xff1a;从功能到体验的全面解析 随着人工智能技术的不断进步&#xff0c;AI论文平台逐渐成为高校学生&#xff0c;尤其是专科生撰写毕业论文的重要…

作者头像 李华
网站建设 2026/4/19 23:23:13

微信小程序vue_uniapp研究生导师日常交互师生交流,考勤打卡任务,请假

文章目录具体实现截图主要技术与实现手段系统设计与实现的思路系统设计方法java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;带文档1万…

作者头像 李华
网站建设 2026/4/21 8:30:02

6、索引算法有哪些?

索引算法有哪些&#xff1f;索引算法有 BTree算法和Hash算法BTree算法BTree是最常用的mysql数据库索引算法&#xff0c;也是mysql默认的算法。因为它不仅可以被用在,>,>,<,<和between这些比较操作符上&#xff0c;而且还可以用于like操作符&#xff0c;只要它的查询…

作者头像 李华
网站建设 2026/4/19 14:04:04

7、索引设计的原则

索引设计的原则适合索引的列是出现在where子句中的列&#xff0c;或者连接子句中指定的列基数较小的类&#xff0c;索引效果较差&#xff0c;没有必要在此列建立索引使用短索引&#xff0c;如果对长字符串列进行索引&#xff0c;应该指定一个前缀长度&#xff0c;这样能够节省大…

作者头像 李华
网站建设 2026/4/17 21:11:18

Java毕设选题推荐:基于Springboot+Vue的旅游攻略分享平台系统基于VUE的旅游信息分享管理平台【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华