基于 Redis 实现的分布式锁----------redisTemplate

分布式锁应用场景大都是用在高并发,大流量场景。当多个进程不在同一个系统中,就需要用分布式锁控制多个进程对资源的访问。本篇介绍的是基于 Redis 实现的分布式锁。首先看两个 Redis 的命令:

SETNX key value

将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。

GETSET key value

自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。

以秒杀为例,基于 Redis 实现的分布式锁,其实就是在秒杀的方法前后进行加锁、解锁操作:

public void orderProductMockDiffUser(String productId) {
    // 加锁
    // ...
    // 解锁
}

下面新建一个 Redis 分布式锁的处理,把加锁和解锁写进来:

@Component
@Slf4j
public class RedisLock {
    @Resource
    private StringRedisTemplate redisTemplate;
    /**
     * 加锁
     * @param key
     * @param value 当前时间+超时时间
     * @return
     */
    public boolean lock(String key, String value) {
        //SETNX命令, 可以设置返回true, 不可以返回false
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
            return true;
        }
        String currentValue = redisTemplate.opsForValue().get(key);
        //如果锁过期
        if (StringUtils.isEmpty(currentValue) && (Long.parseLong(currentValue) < System.currentTimeMillis())) {
            //GETSET命令, 获取上一个锁的时间
            String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(value)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 解锁
     */
    public void unLock(String key, String value) {
        try {
            String currentValue = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Throwable e) {
            log.error("[redis分布式锁] 解锁异常, {}", e.getMessage(), e);
        }
    }
}

使用就很简单了

private static final int TIMEOUT = 10 * 1000; //超时时间10秒
@Autowired
private RedisLock redisLock;
/**
 * 秒杀的方法
 */
public void orderProductMockDiffUser(String productId) {
    //加锁
    long time = System.currentTimeMillis() + TIMEOUT;
    if(!redisLock.lock(productId, String.valueOf(time))) {
        throw new SellException(101, "人也太多了, 换个姿势再试试~");
    };
    //...
    //解锁
    redisLock.unLock(productId, String.valueOf(time));
}

这种方式实现的分布式锁是有缺点的,详情请点击我的下一篇博客

猜你喜欢

转载自blog.csdn.net/alyone_23/article/details/84559935
今日推荐