《知识点扫盲 · Redis 分布式锁》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗

🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍

文章目录

技术简介

Redis 分布式锁是一种利用 Redis 的特性来实现的分布式锁机制,主要用于解决在分布式系统中多个实例对共享资源的并发访问问题。通过使用 Redis 作为锁的存储介质,可以确保在多个服务实例之间的互斥访问。

Redis 分布式锁的基本原理:

  • 加锁:通过 SETNX 命令,尝试设置一个锁的键。如果设置成功,表示获得锁;如果失败,表示锁已经被其他实例持有。
  • 设置过期时间:为了防止死锁,通常在加锁时会设置一个过期时间,确保即使持锁的实例崩溃,锁也会在一定时间后自动释放。
  • 解锁:在完成对共享资源的操作后,释放锁。解锁时需要确保只有持有锁的实例才能解锁,通常通过比较锁的值来实现。

Redis 分布式锁的注意事项:

  1. 锁过期时间: 设置合理的锁过期时间,避免死锁。
  2. 释放: 确保在使用完锁后及时释放锁,避免资源浪费。
  3. 重入锁: 如果需要同一个线程多次获取锁,可以使用可重入锁。
  4. 公平锁: 如果需要按照请求顺序分配锁,可以使用公平锁
  5. 锁竞争: 在高并发场景下,可能会出现锁竞争,需要考虑如何处理锁竞争。

示例说明

编写工具类 RedisLockUtil,代码如下:

java 复制代码
public class RedisLockUtil {

    public static final String LOCK_KEY_PREFIX = "lock:";
    private static final String UNLOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    private static final RedisScript<Long> UNLOCK_REDIS_SCRIPT = new DefaultRedisScript<>(UNLOCK_LUA_SCRIPT, Long.class);

    /**
     * 尝试Redis锁
     *
     * @param lockKey  锁名称
     * @param lockId   锁持有者唯一ID
     * @param duration 过期时间(过期自动释放锁)
     * @param timeUnit 时间单位
     * @return true: 获取锁成功 , false: 获取锁失败
     */
    public static boolean tryLock(@NonNull String lockKey, @NonNull String lockId, long duration, @NonNull TimeUnit timeUnit) {
        return RedisUtil.setIfAbsent(LOCK_KEY_PREFIX.concat(lockKey), lockId, duration, timeUnit);
    }

    /**
     * 释放Redis锁
     *
     * @param lockKey 锁名称
     * @param lockId  锁持有者唯一ID
     */
    public static boolean unlock(@NonNull String lockKey, @NonNull String lockId) {
        Object result = RedisUtil.getRedisTemplate().execute(UNLOCK_REDIS_SCRIPT, Collections.singletonList(LOCK_KEY_PREFIX.concat(lockKey)), lockId);
        return Long.valueOf(1).equals(result);
    }
}

核心工具类逻辑:

java 复制代码
/**
 * 仅在Redis中键不存在时设置键的值并设置过期时间。
 *
 * @param redisKey Redis中的键。
 * @param value    要设置的值。
 * @param expire   键的过期时间。
 * @param timeUnit 过期时间的时间单位。
 * @return 如果成功设置了键值对,则返回true,否则返回false。
 */
public static boolean setIfAbsent(@NonNull String redisKey, Object value, long expire, TimeUnit timeUnit) {
    return checkBool(getRedisTemplate().opsForValue()
            .setIfAbsent(redisKey, value, expire, timeUnit));
}

使用示例:

java 复制代码
    public void doSomething() {
        // 分布式锁标识,根据该标识进行加锁和解锁
        String lockKey = "myLockKey";
        // 随机ID,解锁时用于校验
        String lockId = UUID.randomUUID().toString();
        try {
            // 创建一个60秒后自动过期的锁. 返回true: 获取锁成功,返回false:获取锁失败(开发者自行决定获取锁失败时处理方案)
            boolean status = RedisLockUtil.tryLock(lockKey, lockId, 60, TimeUnit.SECONDS);
            // 获取锁失败
            if (!status) {
                // 执行获取锁失败的业务处理逻辑
                throw ApiException.createEx(ExceptionCodeEnum.REDIS_TRY_GET_LOCK_FAILURE, lockKey);
            }
            // 执行获取锁成功后的业务逻辑
            // ...
        } finally {
            // 解锁状态,true:解锁成功,false:解锁失败
            boolean unlockStatus = RedisLockUtil.unlock(lockKey, lockId);
            if (!unlockStatus) {
                log.error("[Redis分布式锁] 解锁失败, lockKey={}, lockId={}", lockKey, lockId);
            }
        }
    }

总结陈词

此篇文章介绍了 Redis 分布式的基础应用,仅供学习参考。

Redis 分布式锁是一种简单高效的实现分布式锁的方案,可以有效解决分布式系统中数据冲突问题。选择合适的实现方法,注意相关注意事项,可以确保锁的可靠性和性能。

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

相关推荐
jiayou6414 小时前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤1 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
初次攀爬者2 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
爱可生开源社区2 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1773 天前
《从零搭建NestJS项目》
数据库·typescript
加号33 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏3 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐3 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再3 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip
tryCbest3 天前
数据库SQL学习
数据库·sql