Redis中的数据结构-String与List

Posted Frank Q

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis中的数据结构-String与List相关的知识,希望对你有一定的参考价值。

本文中将主要介绍的是Redis中的String与List两种数据结构;

1、Redis可供使用的常用数据结构
2、Redis中String的使用
3、Redis中List的使用
4、Redis中List的实现简单的生产者与消费者的例子


1、Redis可供使用的常用数据结构
Redis中常见使用的五种数据类型

数据类型Value可以作为的方式读写操作
String字符串、整数和浮点数读写整个或者部分字符串
List字符串链表对于字符串两边进行的push与pop操作,按照值查找或删除某个字符串
Set无序的字符串集合,字符串不可以重复插入、删除和读取某个字符串,查看某个字符串是否属于集合,对于集合执行归、并、差操作
Hash无序KV的HashTable插入、删除和读取某项,读写整个Hashtable
Zset字符串结合,每个字符串映射带一个浮点数分数,按照分数排序插入、删除和读取某项,可以根据范围进行查找

2、Redis中String的使用
1)GET、SET、DEL命令,基本上每种数据类型在使用的时候都会用上;

命令使用描述
GETGET key:读取此key对应的value值
SETSET key:修改对应key的value的值
DELDEL key:删除对应key的value的值

效果如下:

当出现了如下错误:

(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

Redis被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用。请查看Redis日志的详细错误信息。

解决办法:
运行config set stop-writes-on-bgsave-error no命令

hadoop:6379> config set stop-writes-on-bgsave-error no
OK

2)对String类型数据进行增减操作(必须保证这条数据的value可以被看为数字)
DECR与INCR命令,效果如下:

3)一次性插入多条数据:
MGET与MSET命令分别是对于多条数据的查询与插入操作;

4)Java代码的操作如下:

    //Redis客户端的对象
    private static Jedis jedis = null;

    @Before
    public void getJedis() 
        jedis = new Jedis("hadoop",6379);
    

    /**
     * 测试redis的String的数据结构功能
     * @throws UnsupportedEncodingException 
     */
    @Test
    public void testString() throws UnsupportedEncodingException 
        //注意中文的编码问题解决方法
        jedis.set("jedis:string:key:sessionId-0001", new String("Session:Jedis:Perfect:中文".getBytes(),"UTF-8"));
        String value = jedis.get("jedis:string:key:sessionId-0001");
        System.out.println(value);

        jedis.mset("jedis:string:key:sessionId-001","demo-001",
                "jedis:string:key:sessionId-002","demo-002",
                "jedis:string:key:sessionId-003","demo-003"
                );

        List<String> results = jedis.mget("jedis:string:key:sessionId-001","jedis:string:key:sessionId-002","jedis:string:key:sessionId-003");

        for (String result : results) 
            System.out.println(result);
        
    

3、Redis中List的使用

Redis中List命令集:

  • LPUSH key value [value …] 在指定Key所关联的List Value的头部插入参数中给出的所有Values。如果该Key不存在,该命令将在插入之前创建一个与该Key关联的空链表,之后再将数据从链表的头部插入。如果该键的Value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。
  • LPUSHX key value 仅有当参数中指定的Key存在时,该命令才会在其所关联的List Value的头部插入参数中给出的Value,否则将不会有任何操作发生。 插入后链表中元素的数量。
  • LRANGE key start stop 该命令的参数start和end都是0-based。即0表示链表头部(leftmost)的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。 返回指定范围内元素的列表。
  • LPOP key 返回并弹出指定Key关联的链表中的第一个元素,即头部元素,。如果该Key不存,返回nil。 链表头部的元素。
  • LLEN key 返回指定Key关联的链表中元素的数量,如果该Key不存在,则返回0。如果与该Key关联的Value的类型不是链表,则返回相关的错误信息。 链表中元素的数量。
  • LREM key count value 在指定Key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的Key不存在,则直接返回0。 返回被删除的元素数量。
  • LSET key index value 设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。如果索引值Index超出了链表中元素的数量范围,该命令将返回相关的错误信息。 (对指定脚标的值进行设置)
  • LINDEX key index 该命令将返回链表中指定位置(index)的元素,index是0-based,表示头部元素,如果index为-1,表示尾部元素。如果与该Key关联的不是链表,该命令将返回相关的错误信息。 返回请求的元素,如果index超出范围,则返回nil。(读出指定脚标的值)
  • LTRIM key start stop 该命令将仅保留指定范围内的元素,从而保证链接中的元素数量相对恒定。start和stop参数都是0-based,0表示头部元素。和其他命令一样,start和stop也可以为负值,-1表示尾部元素。如果start大于链表的尾部,或start大于stop,该命令不错报错,而是返回一个空的链表,与此同时该Key也将被删除。如果stop大于元素的数量,则保留从start开始剩余的所有元素。
  • LINSERT key BEFORE|AFTER pivot value 该命令的功能是在pivot元素的前面或后面插入参数中的元素value。如果Key不存在,该命令将不执行任何操作。如果与Key关联的Value类型不是链表,相关的错误信息将被返回。 成功插入后链表中元素的数量,如果没有找到pivot,返回-1,如果key不存在,返回0。(在指定的某个value前或后插入一个新的value)
  • RPUSH key value [value …] 在指定Key所关联的List Value的尾部插入参数中给出的所有Values。如果该Key不存在,该命令将在插入之前创建一个与该Key关联的空链表,之后再将数据从链表的尾部插入。如果该键的Value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。
  • RPUSHX key value 仅有当参数中指定的Key存在时,该命令才会在其所关联的List Value的尾部插入参数中给出的Value,否则将不会有任何操作发生。 插入后链表中元素的数量。
  • RPOP key 返回并弹出指定Key关联的链表中的最后一个元素,即尾部元素。如果该Key不存,返回nil。链表尾部的元素。
  • RPOPLPUSH source destination 原子性的从与source键关联的链表尾部弹出一个元素,同时再将弹出的元素插入到与destination键关联的链表的头部。如果source键不存在,该命令将返回nil,同时不再做任何其它的操作了。如果source和destination是同一个键,则相当于原子性的将其关联链表中的尾部元素移到该链表的头部。 返回弹出和插入的元素。

1)首先需要注意的是Redis中List数据的头插法与尾插法的使用:

  • 从头部插入数据
    LPUSH listdemo01 value1 value2 value3
  • 从尾部插入数据
    RPUSH listdemo02 value1 value2 value3
    2)其次需要注意的是从尾部和头部弹出元素:
  • 从头部弹出一个元素
    LPOP key
  • 从尾部弹出一个元素
    RPOP key
  • 从一个list的尾部弹出一个元素插入到另一个List(注意使用方法)
    RPOPLPUSH key1 key2

4、Redis中List的实现简单的生产者与消费者的例子

package com.redis.yq;

import java.util.Random;
import java.util.UUID;

import redis.clients.jedis.Jedis;

public class TaskSchedulerSystem 

    protected static Jedis jedis = new Jedis("192.168.1.168",6379);
    /**
     * 模拟生产者
     * @author YQ
     *
     */
    public static class TaskProducer implements Runnable 
        @Override
        public void run() 

            Random random = new Random();

            while (true) 
                try 
                    //一秒到两秒之间
                    Thread.sleep(random.nextInt(1000)+1000);

                    //生成一个任务
                    UUID taskID = UUID.randomUUID();

                    //将一个任务插入到任务队列
                    jedis.lpush("task-queue", taskID.toString());

                    System.out.println("Inest Task Infomation : task-queue : "+taskID.toString());

                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            
        
    

    /**
     * 模拟消费者
     * @author YQ
     *
     */
    public static class TaskConsumer implements Runnable 
        @Override
        public void run() 
            Random random = new Random();
            while(true) 
                //从任务队列中获取任务,并且该任务放到暂存队列
                String taskid = jedis.rpoplpush("task-queue", "tmp-queue");
                //处理任务----业务逻辑
                //模拟成功或者失败的偶然现象
                try 
                    Thread.sleep(1000);
                    System.out.println(taskid + " : " + "ing... ...");
                    //模拟
                    if (random.nextInt(9)%5==0)    //模拟失败情况
                        //将本次处理的任务从暂存队列的tmp-queue中弹回队列"task-queue"
                        jedis.rpoplpush("tmp-queue", "task-queue");
                        System.out.println(taskid + "fail and return");
                     else     //模拟成功
                        jedis.rpop("tmp-queue");
                        System.out.println(taskid + "success and clean");
                    
                 catch (InterruptedException e) 
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                

            
        
    

    public static void main(String[] args) 

        //启动一个生产者线程,模拟任务产生
        new Thread(new TaskProducer()).start();

        try 
            Thread.sleep(500);
         catch (InterruptedException e) 
            e.printStackTrace();
        

        //启动一个消费者线程,模拟任务处理
        new Thread(new TaskConsumer()).start();

        //主线程休眠
        try 
            Thread.sleep(Long.MAX_VALUE);
         catch (InterruptedException e) 
            e.printStackTrace();
        

    

运行结果如下:

以上是关于Redis中的数据结构-String与List的主要内容,如果未能解决你的问题,请参考以下文章

redis

Redis list数据类型

redis中list和hash的基本命令和使用场景

系统学习redis之五——redis数据类型之list类型及操作

Redis特点及在系统中的应用

list操作