Redis的java操作接口与分布式锁

RedisTemplate

分布式锁

 

Redis是一个基于内存的数据库,提供了字符串(String)、散列(Hash)、列表(list)、集合(sets) 和 有序集合(sorted sets)几种数据类型(具体参见Redis简介)。

RedisTemplate

spring-redis中使用了RedisTemplate进行redis的操作,通过泛型的K和V设置键值对的类型;并对五种类型提供对应的操作类:

  • ValueOperations:字符串类型数据操作,通过opsForValue()获取;

  • HashOperations:散列类型的数据操作,通过opsForHash()获取;

  • ListOperations:链表类型的数据操作,通过opsForList()获取;

  • SetOperations:无序集合类型的数据操作,通过opsForSet()获取;

  • ZSetOperations:有序集合类型的数据操作,通过opsForZSet()获取;

Tempate的初始化

以K、V都是String类型为例(复杂Value存储对应对象的Json)。

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, String> template = new RedisTemplate<>();
    template.setConnectionFactory(factory);

    // //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
    // Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(String.class);
    // ObjectMapper om = new ObjectMapper();
    // // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
    // om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    // // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
    // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    // jacksonSeial.setStringMapper(om);
    // // 值采用json序列化
    // template.setValueSerializer(jacksonSeial);
    // template.setHashValueSerializer(jacksonSeial);

    // StringRedisSerializer
    StringRedisSerializer defSerial = new StringRedisSerializer();
    template.setKeySerializer(defSerial);
    template.setValueSerializer(defSerial);

    // 设置hash key 和value序列化模式
    template.setHashKeySerializer(defSerial);
    template.setHashValueSerializer(defSerial);

    template.afterPropertiesSet();
    return template;
}

键值有效期

redis中的键可以设定有效期;但是有效期只能针对整个键值,不能设定到子项:如一个Hash键,要么全部失效,要么全部有效,不能针对某个子项失效

  • template.expire:设定键值的有效期;

  • template.opsForValue().set:可以在设定值的同时,设定有效期。
    只有String类型可以在设定时同时设定有效期,其他类型只能设定之后再通过expire设定。

分布式锁

利用redis键值的性质,可以实现分布式锁:

  • 通过setIfAbsent保证只有一个申请者获得锁;

  • 在设定时设定有效期,避免申请者死掉后,一直占据着锁;

  • 通过UUID保证值的唯一性,在删除前判断,避免意外删除;

public class JRedisLocker{
    static final String LockerPath = "XLocker/";
    private RedisTemplate<String,String> redisService;
    private String lockerName;
    private String lockerValue;
    private int lockSeconds;

    public JRedisLocker(RedisTemplate<String,String> redis, String key, int expireSeconds){
        redisService = redis;
        lockerName = LockerPath + key;
        lockSeconds = expireSeconds;
        lockerValue = "";
    }

    public boolean lock(){
        String strValue = UUID.randomUUID().toString();
        if(redisService.opsForValue().setIfAbsent(lockerName, strValue, lockSeconds, TimeUnit.SECONDS)){
            lockerValue = strValue;
            return true;
        }

        return false;
    }

    public boolean lock(int waitSeconds){
        String strValue = UUID.randomUUID().toString();
        long expire = System.currentTimeMillis() + waitSeconds*1000;
        while(!redisService.opsForValue().setIfAbsent(lockerName, strValue, lockSeconds, TimeUnit.SECONDS)){
            if(expire<System.currentTimeMillis())
                return false;

            Thread.sleep(10);
        }

        lockerValue = strValue;
        return true;
    }

    public boolean unlock(){
        if(lockerValue.equals(redisService.opsForValue().get(lockerName)){
            redisService.delete(lockerName);
            return true;
        }

        return false;
    }

    // 延长锁定时间(在执行任务时间过长时使用)
    public boolean delayLock(){
        if(lockerValue.equals(redisService.opsForValue().get(lockerName)){
            redisService.expire(lockerName, lockSeconds, TimeUnit.SECONDS);
            return true;
        }

        return false;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值