《知识点扫盲 · 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 分布式锁是一种简单高效的实现分布式锁的方案,可以有效解决分布式系统中数据冲突问题。选择合适的实现方法,注意相关注意事项,可以确保锁的可靠性和性能。

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

相关推荐
2501_941805936 小时前
在大阪智能零售场景中构建支付实时处理与高并发顾客行为分析平台的工程设计实践经验分享
数据库
李慕婉学姐6 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
珠海西格电力6 小时前
零碳园区有哪些政策支持?
大数据·数据库·人工智能·物联网·能源
数据大魔方7 小时前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
Chasing Aurora7 小时前
数据库连接+查询优化
数据库·sql·mysql·prompt·约束
倔强的石头_7 小时前
【金仓数据库】ksql 指南(六)—— 创建与管理用户和权限(KingbaseES 安全控制核心)
数据库
奋进的芋圆8 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
小熊officer8 小时前
Python字符串
开发语言·数据库·python
渐暖°8 小时前
JDBC直连ORACLE进行查询
数据库·oracle
萧曵 丶9 小时前
Next-Key Lock、记录锁、间隙锁浅谈
数据库·sql·mysql·mvcc·可重复读·幻读