Jedis,lettuce,RedisTemplate,Redission区别

本文介绍了Jedis、Lettuce、RedisTemplate和Redission这四个与Redis交互的Java库。Jedis是官方推荐,但不支持多线程和异步操作;Lettuce线程安全且可伸缩;RedisTemplate是Spring对Jedis和Lettuce的封装,简化了集成;Redission是一个内存数据网格,提供了多种分布式服务,适用于分布式锁等场景。在使用分布式锁时,需注意设置过期时间、线程安全及原子性操作。

1.Jedis:

Redis官方推荐使用Jedis操作Redis,Jedis的方法和Redis的指令一一对应。

Jedis和lettuce都是可以操作redis的平台

使用时:

导包

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

创建工具类 

public class JedisUtil {

    private  static final JedisPool jedisPool;

    static {
        //设置基本属性
        GenericObjectPoolConfig<Jedis> poolConfig = new JedisPoolConfig();
        //最大连接数
        poolConfig.setMaxTotal(50);
        //最大空闲数
        poolConfig.setMaxIdle(10);

        jedisPool = new JedisPool(poolConfig, "XXX", 6379, 2000, "XXX");
    }

    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
    
}

测试使用:

 /**
     * 测试 使用封装的工具类来使用redis
     */
    @Test
    void test03(){
        Jedis jedis = JedisUtil.getJedis();
        jedis.lpush("lol","abc");
        jedis.lpush("lol","def");
        jedis.lpush("lol","ghj");
        //弹出
        System.out.println(jedis.lrange("lol", 0, -1));
    }

 因为Jedis采用的直连,多个线程操作是不安全的,如果想要避免,得使用jedis pool连接池 ,并且不支持异步

2.lettuce

Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问,同时它是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例

依赖:


        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </dependency>

具体没咋用过

3.RedisTemplate 

redistemplate是spring框架对jedis和lettuce的封装。让spring框架体系能够更加方便的接入redis的功能。

依赖:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

这个依赖包中就包括了jedis 和 lettuce的依赖

基础使用:

先配置自定义RedisTemplate 因为底层默认JDK二进制序列化 不能跨平台使用 

 @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.json());
        template.setHashKeySerializer(RedisSerializer.string());
        template.setHashValueSerializer(RedisSerializer.json());
        return template;
    }

String Hash List Set Zset 基础使用:

/**
     * String -- API
     */
    @Test
    void  test07(){
        //通用指令
        //exists
        System.out.println(redisTemplate.hasKey("a"));
        System.out.println(redisTemplate.hasKey("b"));
        //ttl
        System.out.println(redisTemplate.getExpire("a", TimeUnit.SECONDS));
        System.out.println(redisTemplate.getExpire("b", TimeUnit.SECONDS));
        //expire
        System.out.println(redisTemplate.expire("a", 100,TimeUnit.SECONDS));
        System.out.println(redisTemplate.getExpire("a", TimeUnit.SECONDS));
        redisTemplate.persist("a");
        System.out.println(redisTemplate.getExpire("a", TimeUnit.SECONDS));
    }

    /**
     * String -- API2
     */
    @Test
    void test08(){
        //keys
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("abc","456");

        System.out.println(redisTemplate.keys("*"));
        //dbsize
        System.out.println(redisTemplate.countExistingKeys(redisTemplate.keys("*")));
        redisTemplate.delete("aaa");
        System.out.println(redisTemplate.keys("*"));
        System.out.println(redisTemplate.countExistingKeys(redisTemplate.keys("*")));
    }

    /**
     * Hash --API
     */
    @Test
    void test09(){
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        //hset
        hashOperations.put("number","NO1","金钱");
        hashOperations.put("number","NO2","亲情");
        hashOperations.put("number","NO3","爱情");

        //hmset
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("number","123");
        hashMap.put("age","25");
        hashOperations.putAll("hmset",hashMap);

        //hget
        Object o = hashOperations.get("number", "NO1");
        System.out.println("获取number集合中 no1-key的值:"+o);

        //hkeys
        Set<Object> number = hashOperations.keys("number");
        System.out.println("获取number集合中的所有keys:"+number);

        //hvals
        List<Object> number1 = hashOperations.values("number");
        System.out.println("获取number集合中的所有values:"+number1);

        //hdel
        hashOperations.delete("hmset","age");
        //获取键值对
        System.out.println("获取hmset的键值对"+hashOperations.entries("hmset"));
        hashOperations.put("hmset","age",20);
        System.out.println("获取hmset的age-value值"+hashOperations.get("hmset","age"));

        //hincrby 使变量中的键以double值的大小进行自增长。
        hashOperations.increment("hmset1","number",1);
        System.out.println(hashOperations.get("hmset1","number"));
    }

    /**
     * LIST --API
     */
    @Test
    void test(){
        ListOperations<String, Object> opsForList= redisTemplate.opsForList();
        //lpush rpush
        opsForList.rightPushAll("rpush","a","b","c","d");

        //lrange
        System.out.println("取rpush集合中的所有值:"+opsForList.range("rpush", 0, -1));

        //lpop rpop
        /*Long size = opsForList.size("rpush");
        for (int i = 0; i < size; i++) {
            System.out.println("从rpush集合中弹出:"+opsForList.leftPop("rpush"));
        }*/

        Object object = null;
        while (opsForList.leftPop("rpush") != null){
            System.out.println("从rpush集合中弹出:"+opsForList.leftPop("rpush"));
        }

    }
    /**
     * Set --Api
     */
    @Test
    void test105(){
        SetOperations<String, Object> opsForSet = redisTemplate.opsForSet();
        //sadd
        opsForSet.add("set1", "a","b","c","d","c","a");
        //smembers
        System.out.println(opsForSet.members("set1"));
        //scard
        System.out.println(opsForSet.size("set1"));
        //sismember
        System.out.println(opsForSet.isMember("set1","a"));
        System.out.println(opsForSet.isMember("set1","x"));
        //随机选取
        //srandrem
        System.out.println(opsForSet.randomMembers("set1", 3));
        System.out.println(opsForSet.randomMembers("set1", 3));
        System.out.println(opsForSet.randomMembers("set1", 3));
        System.out.println(opsForSet.members("set1"));
        System.out.println(opsForSet.pop("set1", 1));
        System.out.println(opsForSet.pop("set1", 1));
        System.out.println(opsForSet.members("set1"));
    }

    /**
     * Zset --API
     */
    @Test
    void test11(){
        ZSetOperations<String, Object> opsForZset = redisTemplate.opsForZSet();
        //zadd
        opsForZset.add("zset","数学",80);
        opsForZset.add("zset","物理",70);
        opsForZset.add("zset","英语",140);
        System.out.println("zset中的全部key:"+opsForZset.range("zset",0,-1));

        Set<ZSetOperations.TypedTuple<Object>> zset = opsForZset.rangeWithScores("zset", 0, -1);
        for (ZSetOperations.TypedTuple<Object> o :zset) {
            System.out.println(o.getValue());
            System.out.println(o.getScore());
        }

    }

    /**
     *  Zset --API 方式二:
     *  Arrays.asList()将数组转换为集合后,底层其实还是数组,它返回的是Arrays的一个内部类,体现了适配器模式。
     *  传递的数组必须是对象数组,而不是基本类型。
     */
    @Test
    void test12(){
        ZSetOperations<String, Object> opsForZSet = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> zset2 = new HashSet<>();
        DefaultTypedTuple<Object> t1 = new DefaultTypedTuple<>("历史", 80.0);
        DefaultTypedTuple<Object> t2 = new DefaultTypedTuple<>("政治", 68.0);
        DefaultTypedTuple<Object> t3 = new DefaultTypedTuple<>("地理", 90.0);
        opsForZSet.add("zset2",new HashSet<>(Arrays.asList(t1,t2,t3)));

    }

4.Redission

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括Bitset, Set, MultiMap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish/Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service。Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。(官话)

暂时我用的Redission还不多 只在使用分布式锁时用了下 

在一些场合中 比如在集群,多条指令,就需要分布式锁来进行控制Redis安全性

 

Redission依赖:

<dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

配置类:

/**
     * Redisson 分布式锁
     */

    @Configuration
    public class RedissonConfiguration {
        @Bean
        public RedissonClient redissonClient(){
            Config config=new Config();
            config.useSingleServer().setAddress("redis://xxx");
            config.useSingleServer().setPassword("xxx");
            return Redisson.create(config);
        }
    }

 实际使用:

但是这样会使效率变低(比如秒杀)

/**
     * 使用分布式锁
     */
    @RequestMapping("/lock")
    public void incr2(){
        RLock mylock = redissonClient.getLock("mylock");
        mylock.lock();
        //过期解锁 无需调用unlock
        //mylock.lock(10, TimeUnit.SECONDS);
        //尝试加锁 最多等待2秒 8s过期自动解锁
        //boolean b = mylock.tryLock(2, 8, TimeUnit.SECONDS);
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        Object num = opsForValue.get("num");
        if(num == null){
            opsForValue.set("num","1");
        }else{
            int count=Integer.parseInt(num.toString());
            count++;
            opsForValue.set("num", count+"");
        }
        mylock.unlock();
    }

在使用分布式锁时需要注意

    1.设置过期时间:当前应用加锁,如果宕机,可以正常解锁
    2.解锁只能解自己的锁,不能解别人的锁:线程id
    3.执行结束删除锁:判断+删除,两个指令中间可能会被打断执行,可能删除别人的锁。解决:Lua脚本:可以将多个Redis指令写成一组,一次发送,同时执行,保证原子性

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值