学无先后,达者为师

网站首页 编程语言 正文

RedisTemplate实现setnx分布式锁

作者:毅大师 更新时间: 2022-05-25 编程语言

RedisTemplate由于没有setnx指令,所以需要自定义脚本时间

 一、请直接复制

package com.zy.base.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * redis 工具类
 * @Author ZhangYi
 */
@Component
@Slf4j
public class RedisUtil {

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * lua 脚本
     */
    public static final String SETNX_SCRIPT = "return redis.call('setnx',KEYS[1], ARGV[1])";

    /**
     * redis实现分布式锁
     * @param key
     * @return
     */
    public boolean setNx(String key,int time) {
        //自定义脚本
        DefaultRedisScript script = new DefaultRedisScript<>(SETNX_SCRIPT, List.class);
        //执行脚本,传入参数,由于value没啥用,这里随便写死的"1"
        List rst = redisTemplate.execute(script, Collections.singletonList(key), "1");
        //返回1,表示设置成功,拿到锁
        if(rst.get(0) == 1){
            log.info(key+"成功拿到锁");
            //设置过期时间
            expire(key,time);
            log.info(key+"已成功设置过期时间:"+time +" 秒");
            return true;
        }else{
            long expire = getExpire(key);
            log.info(key+"未拿到到锁,还有"+expire+"释放");
            return false;
        }
    }
    
    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public void expire(String key, long time) {
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete((Collection) CollectionUtils.arrayToList(key));
            }
        }
    }


}

二、使用栗子

redisUtil.setNx("zyLock1",5);

过期时间是为了防止死锁,当业务执行完毕,删除key释放锁

原文链接:https://zhangyi520.blog.csdn.net/article/details/124926230

栏目分类
最近更新