redis分布式锁

       在分布式系统或者前端与后端分离的情况下,如何通过锁来保持数据的排他性访问。比如在前后端分离的系统中,客户端需要领取优惠券,后端通过任务可以领取优惠券,在这种情况下,如何保证领取优惠券的数据正确。一种办法是把领取优惠券的功能抽取一个模块,所有的领取都从这个接口访问;第二种方法基于分布式锁实现。本文简要介绍基于redis实现的分布式锁的方案。

一、基于redis实现

1、引入依赖包

        <dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>

核心方法基于jedis的

 /**
   * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1
   * GB).
   * @param key
   * @param value
   * @param nxxx NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key
   *          if it already exist.
   * @param expx EX|PX, expire time units: EX = seconds; PX = milliseconds
   * @param time expire time in the units of <code>expx</code>
   * @return Status code reply
   */
  public String set(final String key, final String value, final String nxxx, final String expx,

      final long time)

2、获取锁代码

public boolean getLock(String lockKey, String value, int expireTime){
   
    boolean ret = false;
    try{
    do{
        ret = setnxex(lockKey, value, expireTime);
       
        Thread.sleep(500);
        }while(!ret);
   
    }catch(Exception e){    
    }
    return ret;

    }


/**
     * Description: 当前key值不存在则缓存key值 否则不缓存
     * 
     * @param key
     * @param value
     * @param ex 失效时间
     * @param nx 当前key值是否存在
     * @return
     */
    public boolean setnxex(String key, String value, long expireTime) {
        Jedis jedis = this.getConnect();
        try {
            String statusCodeReply = jedis.set(key, value, "nx", "ex", expireTime);
            if (statusCodeReply.equals("OK")) {
                return true;
            }
        } catch (Exception e) {
            log.error(SET_CACHE_ERROR_INFO + e.getMessage());
            log.error("set#Key:" + key + ",Value:" + value + ",expire:" + expireTime);
            return false;
        } finally {
            jedis.close();
        }
        return false;

    }

通过key缓存数据成功,表示成功获取锁。并设置过期时间,防止异常或忘了释放锁。

3、释放锁

    释放锁即是删除缓存key。

public boolean releaseLock(String lockKey, String value){
    Long RELEASE_SUCCESS = 1L;
    Jedis jedis = this.getConnect();
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(value));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false; 
    }

script 是lua脚本,意思是当value与缓存key的值相等时删除key,防止错删。


二、基于redisson实现

        Redisson是架设在 Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。【Redis官方推荐】
Redisson在基于NIO的 Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。

1、引入依赖包

<dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.3.2</version>
    </dependency>

2、redisson初始化

public void init(){
    Config config = new Config();
    config.useSingleServer().setAddress("127.0.0.1:6379");
    config.useSingleServer().setPassword("redis_pass");
   
        redisson = Redisson.create(config);

    }

3、获取锁

public boolean getLock(String name){
    boolean ret = false;
    RLock lock = redisson.getLock(name);
    try {
    ret = lock.tryLock(12000, 5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    return ret;
    }

4、释放锁

public void releaseLock(String name){
    RLock lock = redisson.getLock(name);
    lock.unlock();
    }
    




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值