Redis基本使用一(数据结构常用命令)

开发工具:

  1. Redis3.2;
  2. IDEA;
  3. JDK11;
  4. Gradle4.8;

使用数据结构常用命令:

1.创建项目,开启Redis服务端,导入相关坐标;

重要坐标如下:

implementation('org.springframework.boot:spring-boot-starter-data-redis')
// Redis客户端,用于执行数据结构常用命令
implementation('redis.clients:jedis:2.9.0')

2.添加配置类(SpringBoot默认自动配置,没有特殊需求则可以省略);

配置类代码如下:

package com.lsm1998.redis.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 作者:刘时明
 * 日期:2018/11/12
 * 时间:21:13
 * 说明:
 */
@Configuration
public class RedisConfig
{
    @Bean
    public RedisTemplate initRedisTemplate()
    {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        // 最大空闲数
        poolConfig.setMaxIdle(5);
        // 最大连接数
        poolConfig.setMaxTotal(30);
        // 最大等待毫秒数
        poolConfig.setMaxWaitMillis(1000 * 20);
        // 连接工厂
        JedisConnectionFactory factory=new JedisConnectionFactory(poolConfig);
        // 后初始化方法
        factory.afterPropertiesSet();
        // 序列化器
        //RedisSerializer jdkSerializer=new JdkSerializationRedisSerializer();
        RedisSerializer stringSerializer=new StringRedisSerializer();
        // 定义RedisTemplate,设置连接工厂
        RedisTemplate redisTemplate=new RedisTemplate();
        redisTemplate.setConnectionFactory(factory);
        // 设置序列化器
        redisTemplate.setDefaultSerializer(stringSerializer);
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        return redisTemplate;
    }
}

3.具体程序如下:

package com.lsm1998.redis.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 作者:刘时明
 * 日期:2018/11/12
 * 时间:21:49
 * 说明:Redis基本数据类型
 */
@RestController
public class TestController
{
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 字符数据的常用命令
     *
     * @return
     */
    @GetMapping("test1")
    public Object test1()
    {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        // 设置键值对
        jedis.set("str_1", "新恒结衣");
        // 返回值的字符长度
        System.out.println("值的长度=" + jedis.strlen("str_1"));
        // 获取值
        System.out.println("str_1=" + jedis.get("str_1"));

        // 删除键值对
        //jedis.del("str_1");

        // 修改值,并返回新值
        String str = jedis.getSet("str_1", "泰勒斯威夫特");
        System.out.println("str_1旧值=" + str);
        System.out.println("str_1新值=" + jedis.get("str_1"));

        // 获取子串
        System.out.println("str_1子串=" + jedis.getrange("str_1", 0, jedis.strlen("str_1") / 2));

        // 追加字符,只支持末尾追加
        jedis.append("str_1", "-Red");
        System.out.println("str_1=" + jedis.get("str_1"));

        // 字节数组组成的键值对
        jedis.getSet("str_2".getBytes(), "新恒结衣".getBytes());
        System.out.println("str_2=" + jedis.get("str_2".getBytes()));

        // 关闭连接
        jedis.close();
        return "ok";
    }

    /**
     * 字符数据的计算命令
     *
     * @return
     */
    @GetMapping("test2")
    public Object test2()
    {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.set("num", "0");
        System.out.println("num=" + jedis.get("num"));
        // 指定key值自增
        jedis.incr("num");
        System.out.println("num=" + jedis.get("num"));
        // 指定增加
        jedis.incrBy("num", 10L);
        System.out.println("num=" + jedis.get("num"));
        // 指定key值自减
        jedis.decr("num");
        System.out.println("num=" + jedis.get("num"));
        // 指定减少
        jedis.decrBy("num", 5L);
        System.out.println("num=" + jedis.get("num"));
        // 操作浮点数,此方法没有对应的decrByFloat方法,只需加一个负号即可取得相同效果
        jedis.incrByFloat("num", 3.14);
        System.out.println("num=" + jedis.get("num"));
        jedis.incrByFloat("num", -3.14);
        System.out.println("num=" + jedis.get("num"));
        // 关闭连接
        jedis.close();
        return "ok";
    }

    /**
     * 哈希结构的常用命令
     *
     * @return
     */
    @GetMapping("test3")
    public Object test3()
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        // 指定一个key
        String key = "hash";
        // 一个key下保存多个键值对
        hashOperations.put(key, "k1", "新恒结衣");
        hashOperations.put(key, "k2", new byte[1024]);
        try
        {
            // 此处会抛出异常
            hashOperations.put(key, "k3", new Object());
        } catch (Exception e)
        {
            System.err.println("该对象不可以被序列化");
        }

        // Jedis操作哈希数据结构,与HashOperations有一定区别
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        // jedis.hset保存的是field+value,而与HashOperations则是hashKey+value
        jedis.hset(key, "j1", "泰勒斯威夫特");
        // 编译错误,只支持字符串类型
        //jedis.hset(key, "j2", new ArrayList<>());

        System.out.println("当前大小=" + hashOperations.size(key));
        // 通过遍历key来输出所有的键值对
        hashOperations.keys(key).forEach(k -> System.out.println("key=" + k + ",value=" + hashOperations.get(key, k)));
        return hashOperations.get(key, "k1");
    }

    /**
     * 有序集合结构的常用命令
     *
     * @return
     */
    @GetMapping("test4")
    public Object test4()
    {
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
        String key = "key";
        // 添加元素,key-value-score形式,score代表分数,用于排序
        zSetOperations.add(key, 59, 2.5);
        zSetOperations.add(key, new String("新恒结衣"), 3.0);

        ZSetOperations.TypedTuple<Object> typedTuple1 = new DefaultTypedTuple<>("牛顿", 100.0);
        ZSetOperations.TypedTuple<Object> typedTuple2 = new DefaultTypedTuple<>("伯努利", 98.0);
        Set<ZSetOperations.TypedTuple<Object>> typedTupleSet = new HashSet<>();
        typedTupleSet.add(typedTuple1);
        typedTupleSet.add(typedTuple2);
        // 添加元素,key-Set形式
        zSetOperations.add(key, typedTupleSet);

        long size = zSetOperations.zCard(key);
        // 此时应该有4个元素,因为key-Set其底层会拆为key-value-score形式
        System.out.println("元素个数=" + size);

        // 获取所有元素
        Set temp = zSetOperations.range(key, 0, size - 1);
        long count = zSetOperations.count(key, 80, 100);
        System.out.println("分数80到100之间元素个数=" + count);
        // 返回分数80到100之间的元素集合
        // Set temp = zSetOperations.rangeByScore(key, 80, 100);
        // 删除元素,可以同时传入多个值
        zSetOperations.remove(key, 59);
        // 根据分数范围进行删除
        // zSetOperations.removeRangeByScore(key,80,100);
        temp.forEach(e -> System.out.println(e));

        // Jedis操作ZSet类型
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.zadd(key, -10.0, "hello");
        Set temp2 = jedis.zrevrange(key, 0, jedis.zcard(key) - 1);
        System.out.println("**********华丽的分隔线**********");
        // 此时长度为1
        // 与HashOperations相似,Jedis操作的ZSet和ZSetOperations操作的ZSet是有区别的,二者不能混用
        System.out.println("长度=" + jedis.zcard(key));
        temp2.forEach(e -> System.out.println(e));

        // 计算多个有序集合的并集
        String destKey = "dest_key";
        // 添加一个同value同score的元素
        redisTemplate.opsForZSet().add(destKey, "新恒结衣", 3.0);
        // 添加一个同value但不同score的元素
        redisTemplate.opsForZSet().add(destKey, "新恒结衣", 3.1);
        // 此处结果与unionAndStore(key, key, destKey)一致,结果返回3,代表有3个value相同的元素
        long l = zSetOperations.unionAndStore(key, destKey, destKey);
        System.out.println("相同value元素数量=" + l);
        return "ok";
    }

    /**
     * 链表结构
     *
     * @return
     */
    @GetMapping("test5")
    public Object test5()
    {
        /**
         * Jedis操作链表
         */
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        String key = "j_key";
        // 左端插入
        jedis.lpush(key, "左一", "左二", "左三");
        // 右端插入
        jedis.rpush(key, "右一", "右二", "右三");
        // 下标获取
        System.out.println("链表头部元素=" + jedis.lindex(key, 0));
        // 最右侧删除
        jedis.rpop(key);
        // 最左侧删除
        jedis.lpop(key);
        // 更新元素
        jedis.lset(key, 1, "新值");
        // 尝试最左侧插入,如果key不存在则失败,返回0
        long result = jedis.lpushx(key + "007", "尝试");
        System.out.println("result=" + result);
        // 从左到右删除1个value为‘右二’的元素,0则代表所有
        jedis.lrem(key, 1, "右二");
        // 元素插入,指定BEFORE或者AFTER和元素
        jedis.linsert(key, BinaryClient.LIST_POSITION.AFTER, "新值", "插队元素");
        // 链表裁剪,只保留下标0到5的,裁剪后长度必为end-strrt+1,如果少了则循环补值
        jedis.ltrim(key, 0, 5);
        // 打印0到5的节点值,此时数据为[左二, 新值, 插队元素, 新值, 插队元素, 新值],奇怪的是头元素不会补值
        System.out.println(jedis.lrange(key, 0, 5));
        System.out.println("jedis链表长度=" + jedis.llen(key));
        // 阻塞命令,试图删除最左侧元素,如果没有则等待,直到删除成功或者超时,并返回key和被删除的元素
        List<String> list = jedis.blpop(10 * 1000, key);
        System.out.println("list=" + list);

        /**
         * ListOperations操作链表
         * 写多了就会发现redisTemplate包装类和jedis操作的功能大体一致,但效果不互通
         */
        ListOperations listOperations = redisTemplate.opsForList();
        // 删除前两个‘hello’
        listOperations.remove(key, 2, "hello");
        System.out.println("redisTemplate包装类链表长度=" + listOperations.size(key));
        return "ok";
    }

    /**
     * Set结构
     *
     * @return
     */
    @GetMapping("test6")
    public Object test6()
    {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        String key = "j_key";
        // 插入元素,由于是散列结构,重复元素会覆盖
        jedis.sadd(key, "新恒结衣", "Aragaki", "新恒结衣");
        // 统计个数
        System.out.println("元素个数=" + jedis.scard(key));
        // 判断元素是否存在
        System.out.println("一个元素是否存在?" + jedis.sismember(key, "新恒结衣"));
        // 获取所有键
        Set<String> keys = jedis.keys(key);
        keys.forEach(e -> System.out.println(e));
        // 获取所有值
        jedis.smembers(key).forEach(e -> System.out.println(e));
        // 随机弹出一个元素
        System.out.println(jedis.spop(key));

        SetOperations setOperations = redisTemplate.opsForSet();
        setOperations.add("key_1", "e1", "e2", "e3");
        setOperations.add("key_2", "e0", "e1", "e2");
        // 求差集
        setOperations.difference("key_1", "key_2").forEach(e -> System.out.println(e));
        // 求并集
        setOperations.intersect("key_1", "key_2").forEach(e -> System.out.println(e));
        return "ok";
    }

    /**
     * 基数结构
     *
     * @return
     */
    @GetMapping("test7")
    public Object test7()
    {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        // 添加一个元素
        jedis.pfadd("key", "新恒结衣");
        // 返回基数值
        System.out.println("基数值=" + jedis.pfcount("key"));
        // 保存多个基数值
        jedis.pfmerge("key2", "新恒结衣", "Aragaki");

        HyperLogLogOperations hyperLogLogOperations = redisTemplate.opsForHyperLogLog();
        hyperLogLogOperations.add("key", "新恒结衣");
        hyperLogLogOperations.size("key");
        hyperLogLogOperations.delete("key");
        return "ok";
    }
}

Redis的6种数据结构总结:

  1. 有两种不同的方式可以操作数据,Jedis客户端执行与redisTemplate包装类均有类似的操作方法,但操作的数据不互通;
  2. 都可以实现基本的增删改查;
  3. 除了Hash结构和链表结构外,其余结构都具有一定的运算支持,自增或者求并集等;
  4. 基数类型是最晦涩难懂的,他的原理是压缩数据,将重复的数据转为不重复的基数,减少内存占用;

猜你喜欢

转载自blog.csdn.net/qq_38258310/article/details/83999692