redis分布式锁

概述

在需求开发中,经常会有类似需求:多个数据库操作之间要保证原子性。

如果是单机情况下,可以通过加锁实现操作的原子性,例如使用synchronized关键字,但是如果是分布式环境下,即使加了synchronized关键字,由于存在多个实例,每个实例间的变量并不共享,因此无法保证操作的原子性。

这种情况下,就需要通过分布式锁进行并发控制。

分布式锁需要满足以下条件:

1、对所有实例可见

2、具备超时自动释放的能力,避免由于获取锁的实例宕机导致产生死锁问题

实现

分布式锁有几种实现方式:redis、数据库、zookeeper

如今最流行的方式是通过redis实现分布式锁。

示例:假设数据库存储班级信息,每个学生对应一条记录

|----|----|------|---------|
| id | no | name | monitor |
| 主键 | 学号 | 姓名 | 是否为班长 |

现有交易 competeForMonitor(),需要实现效果为:首个调用交易的学生即为班长

代码实现如下:

java 复制代码
competeForMonitor(int id) {
    // 1、查询班长人数
    int num = classroom.getMonitorMum();    

    // 2、如果当前不存在,则更新为班长
    if (num == 0) {
        classroom.updateById(id);
    }
}

上述代码在没有并发的情况下能够正常执行,但是若存在并发场景,则会产生以下问题:

如果多个线程同时执行了第一步,获取到当前班长数量为0,则会同时执行第二步,将自己设置为班长,与原需求不符。

通过redis的setnx(set not exists如果不存在则设置key)命令可以实现操作的原子性。

由于redis本身为单线程操作,因此当有多个请求并发执行时,redis也能按顺序逐条执行,不会产生并发问题。

java 复制代码
competeForMonitor(int id) {
    // 如果获取锁失败,则自旋尝试获取锁
    while(!stringRedisTemplate.opsForValue().setIfAbsent("lock", "value")) {
    }
    
    // 1、查询班长人数
    int num = classroom.getMonitorMum();    

    // 2、如果当前不存在,则更新为班长
    if (num == 0) {
        classroom.updateById(id);
    }
    // 释放锁
    stringRedisTemplate.delete("lock");
}

问题

上述代码可以实现最基本的分布式锁功能,即加锁和解锁操作。

然而,实际情况可能会有突发问题导致代码运行出现错误。比如,如果A实例获取到锁后挂了,锁未被释放,导致其他实例无法获取锁,影响正常业务,应该如何处理。

给锁加上过期时间?如果中间查询和更新操作实际耗时不确定,过期时间怎么确定?如果实际操作时间大于过期时间,锁被释放了,无法满足原子性怎么办?

相关推荐
heartbeat..4 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
麦聪聊数据6 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
AC赳赳老秦7 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
YMatrix 官方技术社区8 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
辞砚技术录9 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
linweidong9 小时前
C++thread pool(线程池)设计应关注哪些扩展性问题?
java·数据库·c++
欧亚学术10 小时前
突发!刚刚新增17本期刊被剔除!
数据库·论文·sci·期刊·博士·scopus·发表
黑白极客10 小时前
怎么给字符串字段加索引?日志系统 一条更新语句是怎么执行的
java·数据库·sql·mysql·引擎
大厂技术总监下海11 小时前
数据湖加速、实时数仓、统一查询层:Apache Doris 如何成为现代数据架构的“高性能中枢”?
大数据·数据库·算法·apache
LeenixP11 小时前
RK3576-Debian12删除userdata分区
linux·运维·服务器·数据库·debian·开发板