你的浏览器不支持canvas

做你害怕做的事情,然后你会发现,不过如此。

Spring Boot使用Redis的SETNX命令实现分布式锁

时间: 作者: 黄运鑫

本文章属原创文章,未经作者许可,禁止转载,复制,下载,以及用作商业用途。原作者保留所有解释权。


Redis Setnx 命令

  • 基本语法如下:
SETNX KEY_NAME VALUE
  • 当指定的key不存在时,为key设置指定的值;设置成功返回1。设置失败返回0

使用 RedisTemplate 实现锁

  • 加锁、解锁代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.util.Collections;

/**
 * @author hyx
 */
@Service
public class RedisLockService {
    private static final Long SUCCESS = 1L;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取锁
     *
     * @param lockKey
     * @param value
     * @param expireTime 锁有效时间 单位-秒
     * @return
     */
    public boolean getLock(String lockKey, String value, int expireTime) {
        boolean ret = false;
        try {
            //加锁命令,使用SETNX命令加锁,加锁成功返回1
            String script = "if redis.call('setNx',KEYS[1],ARGV[1]) == 1 then if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end else return 0 end";

            RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);

            Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(),
                    new StringRedisSerializer(), Collections.singletonList(lockKey), value, String.valueOf(expireTime));

            //判断加锁成功
            if (SUCCESS.equals(result)) {
                return true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 释放锁
     *
     * @param lockKey
     * @param value
     * @return
     */
    public boolean releaseLock(String lockKey, String value) {

        //解锁命令,解锁成功返回1
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);

        Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(),
                new StringRedisSerializer(), Collections.singletonList(lockKey), value);

        //判断解锁成功
        if (SUCCESS.equals(result)) {
            return true;
        }

        return false;
    }
}
  • 使用实例:
public void update(String id) {
    //加锁
    boolean lock = redisLockService.getLock("lock" + id, id, 300);
    if (!lock) {
        //加锁失败,则不执行
        return;
    }
    try {
        //业务代码
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //解锁
        redisLockService.releaseLock("lock" + id, id);
    }
}

对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。