Redis6大基础数据结构以及在spring中的常用命令

Redis6大基础数据结构:

1.字符串
2.哈希
3.链表
4.集合
5.有序集合
6.基数

字符串:

最基础的数据结构,以键值对形式存储于Redis内部,相当于Map,通过键去找值。
如果是操作字符串redisTemplate的keySerializer和valueSerializer参数都必须是stringRedisSerializer,如果是jdk序列化器那么Redis保存的将不会是数字而是异常。

 
        
        
        
    

字符串分两种情况:
1.不是数字 2是数字
在Spring中,redisTemplate.opsForValue()返回的对象可以操作简单键值对。

1.不是数字

   redisTemplate.opsForValue().set("key1","111");   //保存键为key1,值为111的键值对
       //redisTemplate.delete("key1");                  //删除键为key1的键值对
       //Long length=redisTemplate.opsForValue().size("key1");            //求长度
       //String old_value = (String) redisTemplate.opsForValue().getAndSet("key1","new_111");//设置新值并返回旧值
       //String str = (String) redisTemplate.opsForValue().get("key1");//通过key获取值
       //String str = (String) redisTemplate.opsForValue().get("key1",0,1);//求子串
       //int number = redisTemplate.opsForValue().append("key1","append");追加字符串到末尾,返回新串长度
       //System.out.println(old_value);
       System.out.println(str);
       //System.out.print(length);

2.是数字
注意的是:Redis支持简单的运算,如原字段加上1和整数,或者原子段减去1或者整数,还有一个是原字段加上浮点数,原字段可以是浮点数或者整数。注意关于所有的减法,原有值都必须是整数。注意:无法减去一个double类型的数

public class test {
    @Test
    public void xx(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        //redisTemplate.opsForValue().set("i","9");
        //redisTemplate.opsForValue().increment("i",1);//增加值,可以long或者double,但是减法不行
        //redisTemplate.opsForValue().increment("i",1.2);
        //redisTemplate.getConnectionFactory().getConnection().decr(redisTemplate.getKeySerializer().serialize("i"));
        // 减去1这个可以实现
        //redisTemplate.getConnectionFactory().getConnection().decrBy(redisTemplate.getKeySerializer().serialize("i")
        // ,1);//redisTemplate并没有支持减法。
        printValue(redisTemplate,"i");
    }
    public void printValue(RedisTemplate redisTemplate, String key){
        String i =(String) redisTemplate.opsForValue().get(key);
        System.out.print(i);
    }

}

哈希:

是String类型的field和value的映射表,实际在Redis内存中都是一个个字符串,hash的键值对在内存中是无序的状态,我们可以通过键找到对应的值
需要将spring提供的默认序列化器,即defaultSerializer修改为字符串序列化器 因为spring对hash结构的操作中会涉及map等其他类操作,需要明确他的规则。

由于spring对redis进行了封装,所以需要对redistemplate的配置项进行修改:

  
        
        
        
        
    

如果相对hash结构制定序列化器可以使用hashKeySerializer和hashValueSerializer为hash的filed和value制定序列化器。

注意:
hmset前提是map保存了多个键值对
hgetall会返回所有的键值对
hincrby和bincrbyFloat都采用increment方法
redisTemplate.opsForHash().values(key)相当于hvals命令,他会返回所有的值保存到List对象中,而redisTemplate.opsForHash().keys(key)相当于hkeys,获取所有的键,保存到Set中
redisTemplate.opsForHash().putall()相当于执行了hmset命令,使用了map,是根据默认的序列化器(字符串),所以会用字符串来进行转化,这样才可以执行对应的数值加法。

public class test {
    @Test
    public void xx() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        String key = "hash";
        Map map = new HashMap();
        map.put("f1","val1");
        map.put("f2","11");
        //redisTemplate.opsForHash().putAll(key,map);//相当于hmset,添加一个map
        //redisTemplate.opsForHash().put(key,"f3","val3");相当于hset,添加指定map的一个键值对
        //boolean exists = redisTemplate.opsForHash().hasKey(key,"f3");相当于hexists key filed 查询指定map的键值对是否存在

        //Map map1 =redisTemplate.opsForHash().entries(key);相当于hgetall 返回指定map全部键值对
        //redisTemplate.opsForHash().increment(key,"f2",2);//相当于hincrby,给指定字段加上一个整数
        //redisTemplate.opsForHash().increment(key,"f2",2.2);//相当于hincrbyfloat,给指定字段添加一个浮点数,
        //Object value = redisTemplate.opsForHash().get(key,"f2");//获取指定map中的键值对
        //List list = redisTemplate.opsForHash().values(key);相当于hkeys,获取指定map的values的list集合
        //Set keyList = redisTemplate.opsForHash().keys(key);相当于hkeys,获取指定map的key值
        /*List list =new ArrayList();
        list.add("f1");
        list.add("f2");
        List values = redisTemplate.opsForHash().multiGet(key,list);相当于hmget,获取指定map的指定多个key对应的value值*/
         //System.out.print(values);
       // boolean success= redisTemplate.opsForHash().putIfAbsent(key,"f4","val4");相当于hsetnx,如果指定map不存在对应的键,才设置值
        //Long result = redisTemplate.opsForHash().delete(key,"f1","f2");相当于hdel,删除指定map中的指定键值对
        System.out.print(result);
    }
}

链表操作:

一般存储字符串,是有序的,是双向的,可以存储2的32次方-1节点,redis的链表是双向的。
链表操作有进程安全和不安全的
不安全:

public class test {
    @Test
    public void xx() throws UnsupportedEncodingException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
       redisTemplate.delete("list");//删除链表
       redisTemplate.opsForList().leftPush("list","node1");//插入节点,从头插入
        redisTemplate.opsForList().leftPush("list","node2");//插入节点
       /*List nodeList = new ArrayList();
       for(int i=0;i<2;i++){
           nodeList.add("node:"+i);
       }*/
       //redisTemplate.opsForList().leftPushAll("list",nodeList);//从左插入链表
        //redisTemplate.opsForList().rightPush("list","node4");//从右边插入一个节点
        //String node1 =(String) redisTemplate.opsForList().index("list",0);获取下标为0的节点
        //String lpop =(String) redisTemplate.opsForList().rightPop("list");从左边弹出一个节点
        //String rpop =(String) redisTemplate.opsForList().leftPop("list");从右边弹出一个节点


        /*redisTemplate.getConnectionFactory().getConnection().lInsert("list".getBytes("utf-8"),
                RedisListCommands.Position.BEFORE,
                "node1".getBytes("utf-8"),
                "before_node".getBytes("utf-8")
                );//使用linsert命令在node1前插入一个节点
                */
      /*  redisTemplate.getConnectionFactory().getConnection().lInsert("list".getBytes("utf-8"),
                RedisListCommands.Position.AFTER,
                "node1".getBytes("utf-8"),
                "after_node".getBytes("utf-8")
        );//使用linsert命令在node1后插入一个节点*/
      //redisTemplate.opsForList().leftPushIfPresent("list","head");//判断list是否存在,如果存在则从左边插入head节点
        //redisTemplate.opsForList().rightPushIfPresent("list","end");//判断list是否存在,如果存在则从右边插入end节点
        //List values = redisTemplate.opsForList().range("list",0,1);//从左到右获取指定的节点
        //redisTemplate.opsForList().remove("list",2,"node1");//从左到右删除至多3个node节点
        //redisTemplate.opsForList().set("list",0,"new_node");//给下标为0的节点设置新值
        
        printList(redisTemplate,"list");
    }
    public void printList(RedisTemplate redisTemplate,String key){
        Long size = redisTemplate.opsForList().size(key);//获取指定list节点数
        List values = redisTemplate.opsForList().range(key,0,size);//获取指定链表的内容
        System.out.print(values);
    }
}

以上代表的是redisTemplate对redis链表的操作,left代表左操作,right代表右操作,但是有些命令使用redisTemplate并不支持,比如linsert命令,这个时候需要更底层的命令执行。
如果是多值操作,一般都是使用list封装,然后leftPushAll的方式插入redis

对于链表的阻塞操作,也可以实现,为什么要阻塞呢?因为并发的时候防止多个进程对同一块数据进程读写操作,发生数据安全和一致性的问题。

public class test {
    @Test
    public void xx() throws UnsupportedEncodingException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
       redisTemplate.delete("list1");//删除链表 为了重复数据
        redisTemplate.delete("list2");//删除链表 为了重复数据
        List list1 = new ArrayList();
        for(int i=0;i<5;i++){
            list1.add("1node:"+i);
        }//初始化
        redisTemplate.opsForList().leftPushAll("list1",list1);
       /* redisTemplate.opsForList().leftPop("list",1, TimeUnit.SECONDS);
        redisTemplate.opsForList().rightPop("list",1, TimeUnit.SECONDS);//使用参数超市时间作为阻塞命令区别*/
        List list2 = new ArrayList();
        for(int i=0;i<5;i++){
            list2.add("2node:"+i);
        }//初始化
        redisTemplate.opsForList().leftPushAll("list2",list2);
        //redisTemplate.opsForList().rightPopAndLeftPush("list1","list2");//弹出list1最右边的节点,插入到list2最左边
        //redisTemplate.opsForList().rightPopAndLeftPush("list1","list2",1,TimeUnit.SECONDS);//同上,但是他是阻塞的,意思就是并发
        printList(redisTemplate,"list1");
        printList(redisTemplate,"list2");
    }
    public void printList(RedisTemplate redisTemplate,String key){
        Long size = redisTemplate.opsForList().size(key);//获取指定list节点数
        List values = redisTemplate.opsForList().range(key,0,size);//获取指定链表的内容
        System.out.println(values);
    }
}

阻塞和非阻塞区别:通过设置超时参数进行区分


集合:

不是一个线性结构,而是一个哈希表结构,所以他的插入删除和查找的时间复杂度都是O(1)

1.对于集合而言,他的每一个元素都是不能重复的,插入相同记录会失败
2.无序的
3.每一个元素都是String类型的

集合还有额外的操作,如两个或者以上集合的交集,差集和并集

public class test {
    @Test
    public void xx() throws UnsupportedEncodingException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        Set set = null;
        //redisTemplate.boundSetOps("set1").add("v1","v2","v3");将元素加入列表
        //redisTemplate.boundSetOps("set2").add("s1","s2","s3");
        //Long length = redisTemplate.opsForSet().size("set1");求集合长度
        //set = redisTemplate.opsForSet().difference("set2","set1");求set2中有,但是set1中没有的
        //set = redisTemplate.opsForSet().intersect("set1","set2");求并集
        //boolean exists = redisTemplate.opsForSet().isMember("set1","v1");判断是否存在
        //set = redisTemplate.opsForSet().members("set1");//获取集合所有元素
        //String name = (String) redisTemplate.opsForSet().pop("set1");//随机弹出一个元素
        //String name = (String) redisTemplate.opsForSet().randomMember("set1");随机获取集合中的元素
        //List list = redisTemplate.opsForSet().randomMembers("set1",2L);随机获取2个集合的元素
        //redisTemplate.opsForSet().remove("set1","v1");//删除一个集合的元素,参数可以有多个
        //set = redisTemplate.opsForSet().union("set1","set2");//两个集合的并集
       redisTemplate.opsForSet().differenceAndStore("set1","set2","diff_set");//求差集,保存到diff_set
       redisTemplate.opsForSet().intersectAndStore("set1","set2","inter_set");//求交集,保存到inter_set
       redisTemplate.opsForSet().unionAndStore("set1","set2","union_set");//求并集,保存到union_set
    }
}

还有有序集合:

他有个分数是浮点数根据这个来排序的。
有序集合操作的时候需要封装,DefaultTypedTuple默认实现类实现TypedTuple接口,将带有分数的有序集合的值和分数封装到这个类,通过这个类对象对去对于的值和分数。
对有序集合的封装操作与通过DefaultTypedTuple还有通过RedisZSetCommands下的内部类Range进行范围限定

public class test {
    @Test
    public void xx() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        Set set1 = new HashSet();
        Set set2 = new HashSet();
        int j = 9;
        for (int i = 0; i < 9; i++) {
            j--;
            Double score1 = Double.valueOf(i);
            String value1 = "x" + i;
            Double score2 = Double.valueOf(j);
            String value2 = j % 2 == 1 ? "y" + j : "x" + j;
            ZSetOperations.TypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1);
            set1.add(typedTuple1);
            ZSetOperations.TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2);
            set2.add(typedTuple2);
        }
        redisTemplate.opsForZSet().add("zset1", set1);//插入集合
        redisTemplate.opsForZSet().add("zset2", set2);
        Long size = null;
        //size = redisTemplate.opsForZSet().zCard("zset1");//统计总数
        //size =redisTemplate.opsForZSet().count("zset1",3,6);//求3<=score<=6
        Set set = null;
        //set = redisTemplate.opsForZSet().range("zset1",1,5);//从下标1开始截取5个元素,但是不返回分数,每一个元素都是string
        //set = redisTemplate.opsForZSet().rangeWithScores("zset1",0,-1);
        // 截取集合所有元素,并且对集合按分数排序,并返回分数,每一个元素是TypeTuple,-1代表全部元素
        //printTypedTule(set);
        size = redisTemplate.opsForZSet().intersectAndStore("zset1","zset2","inter_zset");//将zset1和zset2两个集合的交集放入集合inter_zset
        //区间:
        /*RedisZSetCommands.Range range = RedisZSetCommands.Range.range();
        range.lt("x8");//小于
        range.gt("x1");//大于
        range.lte("x8");//小于等于
        range.gte("x1");//大于等于
        set = redisTemplate.opsForZSet().rangeByLex("zset1",range);
        printSet(set);*/

        //限制:
        RedisZSetCommands.Limit limit = RedisZSetCommands.Limit.limit();
        limit.count(4);//限制返回个数为4
        limit.offset(5);//限制从第五个开始截取
        //set = redisTemplate.opsForZSet().rangeByLex("zset1",range,limit);//求区间内的元素,并限制返回四条。
        //Long rank = redisTemplate.opsForZSet().rank("zset1","x0");//求排名 第一个返回0 第二个返回1
        //size = redisTemplate.opsForZSet().remove("zset1","x5","x11");//删除元素,返回删除个数
        //size =redisTemplate.opsForZSet().removeRange("zset1",1,2);//按照排名删除从0开始,这里删除第二个和第三个
        Double dbl = redisTemplate.opsForZSet().incrementScore("zset1","x1",11);//给集合的一个元素的分数加上11 并且返回这个新的分数
        System.out.print(dbl);
    }
    //打印TypedTuple集合
    public void printTypedTule(Set set){
        if(set!=null&&set.isEmpty()){
            return;
        }
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            ZSetOperations.TypedTuple val = (ZSetOperations.TypedTuple)iterator.next();
            System.out.print("{value="+val.getValue()+",score="+val.getScore()+"}\n");
        }
    }
    public void printSet(Set set){
        if(set!=null&&set.isEmpty()){
            return;
        }
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            Object val = iterator.next();
            System.out.print(val+"\t");
        }
        System.out.println();
    }
}

还有基数 :

并不是存储元素,而是给某一个有重复元素的数据集合 评价需要的空间单元数。

你可能感兴趣的:(小白路Redis)