redis 实现分布式锁(一)

1、依赖包

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>1.5.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>

2、redis 工具类

@Component
public class RedisStringUtil {
    /**
     * 注入Redis字符串模板
     */
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 设置值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, String value) {
        this.redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 当前的值 + 1
     *
     * @param key 键
     * @return 返回操作之后的值
     */
    public Long increment(String key) {
        return this.redisTemplate.opsForValue().increment(key, 1);
    }

    /**
     * 当前的值加 + value
     *
     * @param key   键
     * @param value 值
     * @return 返回操作之后的值
     */
    public Long incrementBy(String key, long value) {
        return this.redisTemplate.opsForValue().increment(key, value);
    }

    /**
     * 当前的值 - 1
     *
     * @param key 键
     * @return 返回操作之后的值
     */
    public Long descend(String key) {
        return this.redisTemplate.opsForValue().increment(key, -1);
    }

    /**
     * 当前的值 - value
     *
     * @param key 键
     * @return 返回操作之后的值
     */
    public Long descendBy(String key, long value) {
        return this.redisTemplate.opsForValue().increment(key, -Math.abs(value));
    }

    /**
     * 设置值
     *
     * @param key     键
     * @param value   值
     * @param timeout 超时(秒)
     */
    public void set(String key, String value, long timeout) {
        this.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置值
     *
     * @param key     键
     * @param value   值
     * @param timeout 超时时间
     * @param timeout 超时时间单位
     */
    public void set(String key, String value, long timeout, TimeUnit timeUnit) {
        this.redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 获取值
     *
     * @param key 键
     * @return 获取值
     */
    public String get(String key) {
        return this.redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除
     *
     * @param key 健
     */
    public void delete(String key) {
        this.redisTemplate.delete(key);
    }

    /**
     * 当不存在的时候设置值,
     *
     * @param key           键
     * @param value         值
     * @param expireSeconds 超时时间(单位 秒)
     * @return 成功 返回 OK
     */
    public boolean setIfNotExists(String key, String value, long expireSeconds) {
        return this.setIfNotExists(key, value, expireSeconds, TimeUnit.SECONDS);
    }

    /**
     * 当不存在的时候设置值,
     *
     * @param key      键
     * @param value    值
     * @param expire   超时时间
     * @param timeUnit 超时单位
     * @return 成功 返回 OK
     */
    public boolean setIfNotExists(String key, String value, long expire, TimeUnit timeUnit) {
        final long finalExpire = this.getExpireSeconds(expire, timeUnit);
        String status = this.redisTemplate.execute((RedisCallback<String>) connection -> {
            Object nativeConnection = connection.getNativeConnection();
            if (nativeConnection instanceof JedisCluster) {
                JedisCluster jedisCluster = (JedisCluster) nativeConnection;
                // 只有可以不存在是才设置,并且设置超时时间
                return jedisCluster.set(key, value, "nx", "ex", finalExpire);
            } else {
                Jedis jedis = (Jedis) nativeConnection;
                // 只有可以不存在是才设置,并且设置超时时间
                return jedis.set(key, value, "nx", "ex", finalExpire);
            }
        });
        if (StringUtils.isEmpty(status)) {
            return false;
        } else {
            return "OK".equals(status);
        }
    }

    /**
     * 时间转换  转为 秒
     *
     * @param expire   时间
     * @param timeUnit 单号
     * @return 返回 秒
     */
    private long getExpireSeconds(long expire, TimeUnit timeUnit) {
        //1秒(s) =100厘秒(cs)= 1000 毫秒(ms) = 1,000,000 微秒(μs)
        // = 1,000,000,000 纳秒(ns) = 1,000,000,000,000 皮秒(ps)
        //=1,000,000,000,000,000飞秒(fs)=1,000,000,000,000,000,000仄秒(zs)
        // =1,000,000,000,000,,000,000,000幺秒(ys)=1,000,000,000,000,000,000,000,000渺秒(as)
        switch (timeUnit) {
            case DAYS:
                expire = expire * 24 * 60 * 60;
                break;
            case HOURS:
                expire = expire * 60 * 60;
                break;
            case MINUTES:
                expire = expire * 60;
                break;
            case MILLISECONDS:
                expire = expire / 10 ^ 3;
                break;
            case MICROSECONDS:
                expire = expire / 10 ^ 6;
                break;
            case NANOSECONDS:
                expire = expire / 10 ^ 9;
                break;
            default:
                break;
        }
        return expire;
    }
}

 3、redis 分布锁实现类


@Component
public class RedisLock {
    /**
     * redis操作的类
     */
    @Autowired
    private RedisStringUtil redisStringUtil;
    /**
     * 加锁的值
     */
    private static final String LOCK_VALUE = "TRUE";
    /**
     * 默认超时时间 10s
     */
    private static final int TIME = 10;
    /**
     * 锁的前缀,命名空间
     */
    private static final String PREFIX = "LOCKS:";

    /**
     * 加锁
     *
     * @param key 键
     */
    public boolean lock(String key) {
        return this.redisStringUtil.setIfNotExists(PREFIX.concat(key), LOCK_VALUE, TIME);
    }

    /**
     * 加锁,有超时时间(建议)
     * 避免解锁失败导致死锁
     *
     * @param key  键
     * @param time 超时时间(默认 秒)
     */
    public boolean lock(String key, long time) {
        return this.redisStringUtil.setIfNotExists(PREFIX.concat(key), LOCK_VALUE, time);
    }

    /**
     * 加锁,有超时时间(建议)
     * 避免解锁失败导致死锁
     *
     * @param key  键
     * @param time 超时时间
     * @param unit 超时单位
     */
    public boolean lock(String key, long time, TimeUnit unit) {
        return this.redisStringUtil.setIfNotExists(PREFIX.concat(key), LOCK_VALUE, time, unit);
    }

    /**
     * 解锁
     *
     * @param key 键
     */
    public void unlock(String key) {
        this.redisStringUtil.delete(PREFIX.concat(key));
    }

4、使用方式


    @Autowired
    private RedisLock redisLock;


    public void test() {
        String key = "lock_";
        if (this.redisLock.lock(key)) {
            try {//  需要加锁的代码块
                
            } finally {
                this.redisLock.unlock(key);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_38428623/article/details/82873129