乐观锁的介绍

乐观锁

  1. 乐观锁是一种并发控制机制,如果多种事务并发冲突的概率比较低,所以在数据操作的时候布里吉加锁,在提交时检查数据是否被其他事务修改过,通过版本号(version)或时间戳(Timestamp)实现,确保数据一致性。乐观锁通过版本控制+冲突检测实现高效并发管理,适用于低冲突,高并发的互联网,优势在于无锁设计与高吞吐。

    • 时间戳:用于记录某个事件具体时间的数值或字符串,它的核心作用是唯一标识某一时刻。时间戳是数字化世界的“时间坐标”,它通过标准化的数值或字符串,为事件提供了唯一的时序标识。合理使用时需注意精度、时区和存储格式,以确保跨系统、跨时区的一致性。

    • 乐观锁的核心流程:

      • 读取数据:独缺当前数据和当前版本号。

      • 修改数据:在业务逻辑中处理数据,生成待更新的新数据。

      • 提交更新:执行更新语句时检查版本号是否一致。

        UPDATE table SET data = new_data, version = version + 1 
        WHERE id = target_id AND version = old_version;

      • 检查结果:

        • 若版本不冲突则更新成功

        • 若版本变更,更新失败。

          • 适用:冲突概率低,切业务逻辑允许覆盖或重试。

          • 自动重试:先捕获冲突异常,重新加载最新的数据,重新查询数据库获取最新的版本和数据。然后合并计算:基于最新数据和业务逻辑重新生成待更新的值,进行重试更新:再次执行更新操作,最后限制重试次数,避免无线重试导致资源耗尽。

            @Transactional
            public void updateWithOptimisticLock(Entity entity) {
                int maxRetries = 3;
                for (int i = 0; i < maxRetries; i++) {
                    // 1. 重新查询最新数据
                    Entity latestEntity = entityRepository.findById(entity.getId());
            ​
                    // 2. 合并数据(示例:累加金额)
                    latestEntity.setAmount(latestEntity.getAmount() + entity.getDeltaAmount());
            ​
                    try {
                        // 3. 尝试更新
                        entityRepository.save(latestEntity);
                        return; // 更新成功
                    } catch (OptimisticLockingFailureException e) {
                        // 4. 捕获乐观锁异常,继续重试
                        if (i == maxRetries - 1) {
                            throw new BusinessException("更新失败,请稍后重试");
                        }
                    }
                }
            }

          • 适用:提示用户手动处理:冲突导致业务状态不一致,需要人工介入。

          • 实现步骤:

            • 返回冲突提示:告知用户数据已被修改,

            • 展示新旧数据差异。

            • 用户决策,选择是否覆盖,合并或放弃。

              // 提交更新请求后,后端返回冲突错误
              if (error.code === 'OPTIMISTIC_LOCK_CONFLICT') {
                  // 弹窗提示用户,展示新旧数据对比
                  showConflictDialog(oldData, newData, serverData);
              }

          • 基于业务的合并逻辑

            • 适用场景:冲突可自动化解决(计数器,库存扣减)

            • 实现步骤:

              • 定义合并规则:例如库存中扣减冲突时:基于最新值重新进行计算。

              • 无需用户介入:在重试逻辑中完成自动合并

              • -- 直接基于当前值计算,而非依赖旧版本
                UPDATE product SET stock = stock - 1 WHERE id = 1001 AND stock > 0;

    • 注意事项:

      1. 重试次数的权衡:
      - 重试次数多,性能下降。
      - 重试次数少,用户体验差。
      - 建议3~5次,结合指数退避策略
      2. 避免ABA问题:
          - 版本号可能绕回原值(如版本号的循环使用)
          - 使用不可逆的版本号(时间戳,自增长整形)
      3. 分布式系统扩展:
          - 分布式锁的辅助:在高并发场景下,结合分布式锁,减少冲突概率。
          - 版本号全局唯一:确保分布式华景终版本号的严格递增。
      4. 事务边界控制:
          - 短事务:尽量缩短事务时长,减少冲突窗口
          - 避免长事务:长时间的事务会增大并发冲突的概率。
  2. 总结:乐观锁检测到版本冲突时,核心逻辑是:

    1. 识别冲突:通过影响行数或异常捕获确认冲突发生。

    2. 选择策略:根据业务需求选择自动重试,用户介入或业务合并。

    3. 保证最终一致性:通过合理的重试或合并逻辑确保数据正确性。

你可能感兴趣的:(redis,java,数据库,大数据,intellij-idea)