redis--乐观锁--粗粒度锁

来源:互联网 发布:勇者之塔祈祷数据 编辑:程序博客网 时间:2024/05/30 13:42

一、redis锁的应用

redis锁的引用请参考[redis锁](http://blog.csdn.net/liu20111590/article/details/52840999)假如使用redis的watch监控一个或者多个key,这些key是集合数据,我们将这种锁称为粗粒度锁(类似于数据库中的表锁的功能)

二、redis粗粒度锁缺点

因为每次的操作,只会涉及到集合key的某一个值。我们对整个key进行监控,导致碰撞几率提高,从而使多数的事务被取消。事实上这些被取消的事务有很多是互相不影响的。

 举个例子现在有一个市场(SET),里面存放了一些货物(货物1、货物2、货物3),有三个消费者(消费者A、消费者B、消费者C)。消费者A想购买货物1,消费者B想购买货物2,消费者C想购买货物3。三个人同时拿到货物,同时去付款(这个时候是竞争关系)。我们假设三个都提交了付款的请求,消费者A首先付款成功。这个时候因为市场(SET)中数据发生了变化,导致后面的事务都被取消掉了。

这种时候其实他们三个人是互不影响,但是因为我们使用了粗粒度锁,导致一些不需要取消的事务被取消。

这个时候我们需要细粒度锁来对数据加锁,减少碰撞的概率。

下面贴一段获取粗粒度锁的代码

/**     * 对某一个key进行加锁     * @param lockKey     * @return     */    public String lock(String lockKey){        AssertLock.isTrue(!StringUtils.isEmpty(lockKey),"lockKey不能为空");        String uuid = UUID.randomUUID().toString().replace("-","");        try {            if(redisTemplate.opsForValue().setIfAbsent(LockUtils.commonLockKey(lockKey),uuid)){                return uuid;            }            return null;        }catch (Exception e){            logger.error("获取锁失败",e);        }        return null;    }
 /**     * 释放锁     * @param lockKey     * @param uuid     * @return     */    public boolean unLock(String lockKey,String uuid){        AssertLock.isTrue(!StringUtils.isEmpty(lockKey),"lockKey不能为空");        AssertLock.isTrue(!StringUtils.isEmpty(uuid),"uuid不能为空");        try {            if(StringUtils.equals(redisTemplate.opsForValue().get(LockUtils.commonLockKey(lockKey)),uuid)){                return redisTemplate.expire(LockUtils.commonLockKey(lockKey),0L,TimeUnit.MILLISECONDS);            }            return false;        }catch (Exception e){            logger.error("释放锁失败",e);        }        return false;    }
/**     * 强制释放某个锁(慎用)     * @param lockKey     */    public void forceUnLock(String lockKey){        AssertLock.isTrue(!StringUtils.isEmpty(lockKey),"lockKey不能为空");        redisTemplate.expire(LockUtils.commonLockKey(lockKey),0L,TimeUnit.MILLISECONDS);    }
0 0
原创粉丝点击