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

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

相关推荐
荒川之神6 分钟前
ORACLE 闪回技术简介
数据库·oracle
ZHOU西口1 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
zmd-zk1 小时前
kafka+zookeeper的搭建
大数据·分布式·zookeeper·中间件·kafka
时差9532 小时前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
让学习成为一种生活方式2 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
秋意钟2 小时前
MySQL日期类型选择建议
数据库·mysql
Dxy12393102163 小时前
python下载pdf
数据库·python·pdf
桀桀桀桀桀桀3 小时前
数据库中的用户管理和权限管理
数据库·mysql
superman超哥5 小时前
04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索
数据库·oracle·性能优化·dba
用户8007165452005 小时前
HTAP数据库国产化改造技术可行性方案分析
数据库