精华内容
下载资源
问答
  • 时长敲一下,帮助回忆一下redis的命令,提神醒脑 package com.darwin.redis.jedis; import redis.clients.jedis.BinaryClient; import redis.clients.jedis.GeoUnit; import redis.clients.jedis.Jedis; import ...

    时长敲一下,帮助回忆一下redis的命令,提神醒脑

    package com.darwin.redis.jedis;
    
    import redis.clients.jedis.BinaryClient;
    import redis.clients.jedis.GeoUnit;
    import redis.clients.jedis.Jedis;
    
    import java.util.HashMap;
    
    /**
     * Jedis操作REDIS数据库
     *
     * @author yanghang
     */
    public class JedisTest {
    
        public static void main(String[] args) {
            // 创建jedis客户端对象
            Jedis jedis = new Jedis("192.168.100.151", 6379);
    
            // opsBase(jedis);
    
            // opsString(jedis);
    
            // opsList(jedis);
    
            // opsHash(jedis);
    
            // opsSet(jedis);
    
            // opsSortedSet(jedis);
    
            // opsHyperLogLog(jedis);
    
            // opsGeo(jedis);
    
            // opsBitMaps(jedis);
    
            // 关闭jedis客户端对象
            jedis.close();
        }
    
        /**
         * 使用jedis的基本操作
         */
        private static void opsBase(Jedis jedis) {
            System.out.println("向redis中设置一个key " + jedis.set("key1", "value1"));
            System.out.println("向redis中设置一个key " + jedis.set("key2", "value2"));
    
            System.out.println("选择redis的一个数据库 " + jedis.select(0));
            System.out.println("查看当前数据库的大小 " + jedis.dbSize());
            System.out.println("查看redis中所有的key " + jedis.keys("*"));
            System.out.println("查看某个键对应值的数据类型 " + jedis.type("key1"));
            System.out.println("判断redis中是否存在一个key " + jedis.exists("key1"));
            System.out.println("设置redis中的一个key的过期时间 " + jedis.expire("key1", 10));
            System.out.println("查看redis中的这个key还有多长时间过期 " + jedis.ttl("key1"));
            System.out.println("删除redis中的一个键值对 " + jedis.del("key1"));
            System.out.println("清空当前的数据库 " + jedis.flushDB());
            System.out.println("清空所有的数据库 " + jedis.flushAll());
            System.out.println("将当前的数据库的一个键值对移动到另外一个数据库 " + jedis.move("key2", 1));
        }
    
        /**
         * 使用jedis操作string类型的数据
         */
        private static void opsString(Jedis jedis) {
            System.out.println("向redis中设置一个key " + jedis.set("key1", "value1"));
            System.out.println("只有当key不存在的时候再向redis中设置 " + jedis.setnx("key1", "value2"));
            System.out.println("向redis中设置一个key并设置过期时间 " + jedis.setex("key2", 10, "value2"));
            System.out.println("向redis中的某个key的值追加字符串 " + jedis.append("key1", "2"));
            System.out.println("获取redis中某个key对应的值 " + jedis.get("key1"));
            System.out.println("返回redis中某个key对应的值的长度大小 " + jedis.strlen("key1"));
            System.out.println("使用某个字符串从指定开始位置覆盖key对应的值到相同长度 " + jedis.setrange("key1", 0, "yh"));
            System.out.println("获取指定索引区间的字符串 " + jedis.getrange("key1", 0, 1));
            System.out.println("批量设置key和value " + jedis.mset("key3", "value3", "key4", "value4", "key5", "1"));
            System.out.println("批量获取redis中的值 " + jedis.mget("key3", "key4", "key5"));
            System.out.println("将redis中key对应的值加一 " + jedis.incr("key5"));
            System.out.println("将redis中key对应的值加指定的步长 " + jedis.incrBy("key5", 2));
            System.out.println("将redis中key对应的值减一 " + jedis.decr("key5"));
            System.out.println("将redis中key对应的值减指定的步长  " + jedis.decrBy("key5", 2));
        }
    
        /**
         * 使用jedis操作list类型的数据
         */
        private static void opsList(Jedis jedis) {
            System.out.println("从左边向集合中添加元素 " + jedis.lpush("list1", "value1"));
            System.out.println("从右边向集合中添加元素 " + jedis.rpush("list1", "value2"));
            System.out.println("从集合的左边弹出一个元素 " + jedis.lpop("list1"));
            System.out.println("从集合的右边弹出一个元素 " + jedis.rpop("list1"));
            System.out.println("从左边向集合中添加元素 " + jedis.lpush("list1", "value1"));
            System.out.println("从右边向集合中添加元素 " + jedis.rpush("list1", "value2"));
            System.out.println("查看集合中元素的数量 " + jedis.llen("list1"));
            System.out.println("覆盖集合中指定位置的key的值 " + jedis.lset("list1", 0, "value"));
            System.out.println("从后往前删除两个集合中指定值的元素 " + jedis.lrem("list1", -2, "value2"));
            System.out.println("获取集合中指定下标的元素 " + jedis.lindex("list1", 0));
            System.out.println("在制定元素之前或者之后插入一个元素" + jedis.linsert("list1", BinaryClient.LIST_POSITION.BEFORE, "value", "before"));
            System.out.println("列举集合中的所有元素 " + jedis.lrange("list1", 0, -1));
        }
    
        /**
         * 使用jedis操作hash类型的数据
         */
        private static void opsHash(Jedis jedis) {
            System.out.println("向redis中的key对应的map中put一个值 " + jedis.hset("map1", "key1", "value1"));
            System.out.println("向redis中的key对应的map中put多个值 " + jedis.hmset("map1", new HashMap<String,String>(8) {
                {
                    this.put("key2", "value2");
                    this.put("key3", "value3");
                    this.put("key4", "1");
                }
            }));
            System.out.println("获取redis中key对应map的某个值 " + jedis.hget("map1", "key1"));
            System.out.println("获取redis中key对应map的多个值 " + jedis.hmget("map1", "key1", "key2"));
            System.out.println("获取redis中key对应map的键值对数量 " + jedis.hlen("map1"));
            System.out.println("获取redis中key对应map的所有的key的value的值 " + jedis.hgetAll("map1"));
            System.out.println("获取redis中key对应map的所有的键 " + jedis.hkeys("map1"));
            System.out.println("获取redis中key对应map的所有的值 " + jedis.hvals("map1"));
            System.out.println("如果map对应的key不存在才设置 " + jedis.hsetnx("map1","key4", "2"));
            System.out.println("给map中的某个key对应的值增长对应的值 " + jedis.hincrBy("map1", "key4", 2));
        }
    
        /**
         * 使用jedis操作set类型的数据
         */
        private static void opsSet(Jedis jedis) {
            System.out.println("向set中添加一个或多个元素 " + jedis.sadd("set1", "value1", "value2", "value3", "value4", "value5", "value6"));
            System.out.println("获得set中的元素个数 " + jedis.scard("set1"));
            System.out.println("判断set中是否存在某个元素 " + jedis.sismember("set1", "value1"));
            System.out.println("获得set中的所有元素 " + jedis.smembers("set1"));
            System.out.println("删除set中的一个或者多个元素 " + jedis.srem("set1", "value5", "value6"));
            System.out.println("随机弹出set中的某个元素 " + jedis.spop("set1"));
    
            System.out.println("向set中添加一个或多个元素 " + jedis.sadd("set2", "value1", "value2"));
    
            System.out.println("获得两个set的差集 " + jedis.sdiff("set1", "set2"));
            System.out.println("获得两个set的差集并转储到另外一个set中 " + jedis.sdiffstore("set3", "set1", "set2"));
            System.out.println("获得两个set的交集 " + jedis.sinter("set1", "set2"));
            System.out.println("获得两个set的交集并转储到另外一个set中 " + jedis.sinterstore("set3", "set1", "set2"));
            System.out.println("获得两个set的并集 " + jedis.sunion("set1", "set2"));
            System.out.println("获得两个set的并集并转储到另外一个set中 " + jedis.sunionstore("set3", "set1", "set2"));
            System.out.println("获得set中的所有元素 " + jedis.smembers("set3"));
        }
    
        /**
         * 使用jedis操作zset类型的数据
         * 带分数输出值的时候返回的是字节数组
         */
        private static void opsSortedSet(Jedis jedis) {
            System.out.println("向zset中添加一个元素 " + jedis.zadd("sortedSet1",10,"value"));
            System.out.println("向zset中添加多个元素 " + jedis.zadd("sortedSet1", new HashMap<String, Double>(8) {
                {
                    this.put("value1", 20D);
                    this.put("value2", 30D);
                    this.put("value3", 40D);
                    this.put("value4", 50D);
                }
            }));
            System.out.println("统计zset中的元素个数 " + jedis.zcard("sortedSet1"));
            System.out.println("修改zset中某个元素的分数 " + jedis.zincrby("sortedSet1",-10D,"value"));
            System.out.println("删除zset中的一个或多个元素 " + jedis.zrem("sortedSet1", "value3", "value4"));
            System.out.println("正序获取zset中指定索引范围内的元素 " + jedis.zrange("sortedSet1", 0, -1));
            System.out.println("正序获取zset中指定索引范围内的元素及元素的分数" + jedis.zrangeWithScores("sortedSet1", 0, -1));
            System.out.println("正序获取zset中指定分数范围内的元素 " + jedis.zrangeByScore("sortedSet1", 0, 40));
            System.out.println("正序获取zset中指定分数范围内的元素及元素的分数" + jedis.zrangeWithScores("sortedSet1", 0, 40));
            System.out.println("逆序获取zset中指定索引范围内的元素 " + jedis.zrevrange("sortedSet1", 0, -1));
            System.out.println("逆序获取zset中指定索引范围内的元素及元素的分数" + jedis.zrevrangeWithScores("sortedSet1", 0, -1));
            System.out.println("逆序获取zset中指定分数范围内的元素 " + jedis.zrevrangeByScore("sortedSet1", 40, 0));
            System.out.println("逆序获取zset中指定分数范围内的元素及元素的分数" + jedis.zrevrangeByScoreWithScores("sortedSet1", 40, 0));
        }
    
        /**
         * 使用jedis测试基数数据类型
         */
        private static void opsHyperLogLog(Jedis jedis) {
            System.out.println("向一个数据组中添加数据 " + jedis.pfadd("hyperLogLog", "a", "b", "c", "d", "e", "f", "a", "a", "b"));
            System.out.println("向一个数据组中添加数据 " + jedis.pfadd("hyperLogLog1", "a", "b", "c", "d"));
            jedis.pfmerge("hyperLogLog0","hyperLogLog", "hyperLogLog1");
            System.out.println("输出指定key的基数是多少 " + jedis.pfcount("hyperLogLog0"));
        }
    
        /**
         * 使用jedis操作geospatial类型的数据
         */
        private static void opsGeo(Jedis jedis) {
            System.out.println("向geo中添加地图位置信息 " + jedis.geoadd("geo1", 116.404269d, 39.91582d, "beijing"));
            System.out.println("向geo中添加地图位置信息 " + jedis.geoadd("geo1", 121.478799d, 31.235456d, "shanghai"));
    
            System.out.println("返回某几个地点的地理位置信息 " + jedis.geopos("geo1","beijing", "shanghai"));
            System.out.println("返回两个地点之间的直线距离 " + jedis.geodist("geo1", "beijing", "shanghai"));
            System.out.println("返回指定经纬度多少距离以内的元素 " + jedis.georadius("geo1", 116.404269d, 39.91582d,1500, GeoUnit.KM));
            System.out.println("返回指定元素多少距离以内的元素 " + jedis.georadiusByMember("geo1", "beijing",1500, GeoUnit.KM));
        }
    
        /**
         * 使用jedis操作bitmaps类型的数据
         */
        private static void opsBitMaps(Jedis jedis) {
            System.out.println("向bit中设置数据" + jedis.setbit("bit1",0,true));
            System.out.println("向bit中设置数据" + jedis.setbit("bit1",5,false));
            System.out.println("向bit中设置数据" + jedis.setbit("bit1",10,false));
    
            System.out.println("获取指定索引上的数字 " + jedis.getbit("bit1",4));
            System.out.println("返回bitmaps上共有多少true " + jedis.bitcount("bit1"));
        }
    }
    
    展开全文
  • Redis 数据类型

    2021-01-26 09:26:52
    Redis 数据类型Redis 的五大基本数据类型String(字符串)应用场景常用命令List(列表)应用场景常用命令Hash(字典)应用场景常用命令Set(集合)应用场景常用命令ZSet(有序集合)应用场景常用命令跳跃表Redis特殊...

    Redis 的五大基本数据类型

    String(字符串)

    应用场景

    1. incr key 自增命令实现 计数器(文章阅读量)
    2. JSON对象缓存等

    常用命令

    String常用命令

    List(列表)

    相当于linkedList,链表不是数组

    应用场景

    1. 消息排队,消息队列 (使用Lpush 和 Rpop 命令, 左边存,右边取)
    2. 栈( Lpush Lpop , 左边存, 左边取)

    常用命令

    List常用命令

    Hash(字典)

    相当于HashMap,数组+链表

    应用场景

    适合存放经常变动的对象, 可以直接修改某个属性,而不需要跟string类型一样JSON先转化成实体类在修改

    常用命令

    Hash 常用命令

    Set(集合)

    相当于HashSet, 键值对是无序,唯一的

    应用场景

    1. 共同好友,共同关注(两个set集合使用 sinter key1 key2取交集)
    2. 可能认识的人(使用sdiff key1 key2 取差集, key1 存在 key2 不存在的值)
    3. 点赞功能(新增 sadd key value, 取消 srem key value, 统计 scard key 等)
    4. 随机抽奖功能(spop key 随机删除元素或使用 srandmembet key 随机抽取元素)

    常用命令

    Set 常用命令

    ZSet(有序集合)

    键值对唯一,还可以为每个value赋值一个值,用来代表排序权重.内部是跳跃表数据结构实现

    应用场景

    热点新闻(点击阅读自增ZINCRBY key 步长 value,排序获取前10条热点新闻ZREVRANGE key 0 9 withscores )

    常用命令

    ZSet 常用命令

    跳跃表

    跳跃表是基于多指针有序链表实现,可以看成多个有序链表,在查找时从上层指针开始查找,找到对应的取经后再到下一层查找

    跳跃表

    跳跃表优点

    1. 插入速度非常快,不需要进行旋转灯查找来维护平衡性
    2. 更容易实现
    3. 支持无锁操作

    Redis 三种特殊数据类型

    1. Geospatial 地理位置(GEO)
    2. Hyperloglog 统计
    3. Bitmap 位图

    Geospatial 地理位置(GEO)

    官方文档: https://www.redis.net.cn/order/3685.html

    getadd

    添加地理位置

    # 规则:两级无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
    # 有效的经度从-180度到180度。
    # 有效的纬度从-85.05112878度到85.05112878度。
    # 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
    # 127.0.0.1:6379> geoadd china:city 39.90 116.40 beijin
    (error) ERR invalid longitude,latitude pair 39.900000,116.400000
    # 参数 key 值()
    127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
    (integer) 1
    127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
    (integer) 1
    127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shengzhen
    (integer) 2
    127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
    (integer) 2
    

    getpos

    获得当前定位:一定是一个坐标值

    127.0.0.1:6379> GEOPOS china:city beijing # 获取指定的城市的经度和纬度!
    1) 1) "116.39999896287918091"
    2) "39.90000009167092543"
    127.0.0.1:6379> GEOPOS china:city beijing chongqin
    1) 1) "116.39999896287918091"
    2) "39.90000009167092543"
    2) 1) "106.49999767541885376"
    2) "29.52999957900659211"
    

    GEODIST

    两人之间的直线距离

    单位:

    • m 表示单位为米。
    • km 表示单位为千米。
    • mi 表示单位为英里。
    • ft 表示单位为英尺。
    127.0.0.1:6379> GEODIST china:city beijing shanghai km # 查看上海到北京的直线距离
    "1067.3788"
    127.0.0.1:6379> GEODIST china:city beijing chongqin km # 查看重庆到北京的直线距离
    "1464.0708"
    

    GEORADIUS

    以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素。
    应用场景: 我附近的人,获取附近人地址定位, 通过半径查询

    127.0.0.1:6379> GEORADIUS china:city 110 30 500 km # 以110,30 这个经纬度为中心,寻
    找方圆500km内的城市
    1) "chongqi"
    2) "xian"
    127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist # 显示到中间距离的位置
    1) 1) "chongqi"
    2) "341.9374"
    2) 1) "xian"
    2) "483.8340"
    127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord # 显示他人的定位信息
    1) 1) "chongqi"
    2) 1) "106.49999767541885376"
    2) "29.52999957900659211"
    2) 1) "xian"
    2) 1) "108.96000176668167114"
    2) "34.25999964418929977"
    127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1 #
    筛选出指定的结果!
    1) 1) "chongqi"
    2) "341.9374"
    3) 1) "106.49999767541885376"
    2) "29.52999957900659211"
    

    GEORADIUSBYMEMBER

    和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点
    应用场景: 根据溺水人员地理位置获取附近的救援人员

    # 找出位于指定元素周围的其他元素!
    127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
    1) "beijing"
    2) "xian"
    127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km
    1) "hangzhou"
    2) "shanghai"
    

    GEOHASH

    返回一个或多个位置元素的 Geohash 表示

    127.0.0.1:6379> geohash china:city beijing chongqin
    1) "wx4fbxxfke0"
    2) "wm5xzrybty0"
    

    其他

    GEO 底层的实现原理其实就是 Zset!我们可以使用Zset命令来操作geo!

    127.0.0.1:6379> ZRANGE china:city 0 -1 # 查看地图中全部的元素
    1) "chongqi"
    2) "xian"
    3) "shengzhen"
    4) "hangzhou"
    5) "shanghai"
    6) "beijing"
    127.0.0.1:6379> zrem china:city beijing # 移除指定元素!
    (integer) 1
    127.0.0.1:6379> ZRANGE china:city 0 -1
    1) "chongqi"
    2) "xian"
    3) "shengzhen"
    4) "hangzhou"
    5) "shanghai"
    

    Hyperloglog 统计

    优点: 占用内存是固定的, 只需要 12KB 内存,从内存角度首页该类型
    缺点: 0.81% 的错误率.
    允许容错,使用Hyperloglog , 否则使用set

    应用场景

    网页的 UV (一个人访问一个网站多次,但是还是算作一个人!)

    • 传统的方式, set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断 !
    • 这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;
    127.0.0.1:6379> PFadd mykey a b c d e f g h i j # 创建第一组元素 mykey
    (integer) 1
    127.0.0.1:6379> PFCOUNT mykey # 统计 mykey 元素的基数数量
    (integer) 10
    127.0.0.1:6379> PFadd mykey2 i j z x c v b n m # 创建第二组元素 mykey2
    (integer) 1
    127.0.0.1:6379> PFCOUNT mykey2
    (integer) 9
    127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 # 合并两组 mykey mykey2 => mykey3 并集
    OK
    127.0.0.1:6379> PFCOUNT mykey3 # 看并集的数量!
    (integer) 15
    

    Bitmap 位图

    数据结构 都是二进制位进行记录,只有0 和 1 两个状态

    应用场景

    统计用户信息活跃与不活跃, 登录与未登录,打卡, 365天打卡情况, 两个状态的都可以使用该类型

    统计一周打卡情况
    统计打卡

    127.0.0.1:6379> getbit sign 3 # 查看周四是否打卡
    (integer) 1
    127.0.0.1:6379> getbit sign 6 # 查看周天是否打卡
    (integer) 0
    127.0.0.1:6379> bitcount sign # 统计这周的打卡记录,就可以看到是否有全勤!
    (integer) 3
    
    展开全文
  • redis八种基本数据类型及其应用

    千次阅读 2020-01-21 16:22:22
    redis八种基本数据类型及其应用 文章目录redis八种基本数据类型及其应用1.简介2.安装redis3.基本命令3.1SET命令4.基本数据类型4.1 String 字符串存储原理String的三种编码redis SDSembstr和raw应用场景4.2 Hash 哈希...

    redis八种基本数据类型及其应用

    1.简介

    Redis是一个开源的,内存中的数据结构存储系统,它可以用做数据库,缓存和消息中间件。

    支持多种类型的数据结构

    • 字符串 strings
    • 散列 hashes
    • 列表 lists
    • 集合 sets
    • 有序集合 sorted sets
    • bitmaps
    • hyperloglogs
    • 地理空间 geospatial 索引半径查询

    支持每秒10w次查询请求

    2.安装redis

    Linux CentOS7安装和启动redis

    设置alias方便操作

    ls |grep redis #找到redis的安装路径
    alias rcli='/usr/bin/redis-cli' #设置别名
    #使用别名登录
    rcli
    

    3.基本命令

    推荐网站 http://redisdoc.com/
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h82HM4Tu-1579594343657)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120110919117.png)]

    3.1SET命令

    网站上已经介绍的很清楚了,本文就不赘述了,我们直接看效果。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRrAAhTJ-1579594343659)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120111238082.png)]
    这有个小问题 (error) NOAUTH Authentication required. 提示没有认证。我们需要输入密码即可

    AUTH password

    • set qingshan 666 设置key=qingshan value=666
    • get qingshan 获取key=qingshan的value值

    那么我们一般 set 的数据在redis中是什么类型?

    type qingshan - > string
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1vKR6yZ-1579594343659)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120111949262.png)]

    4.基本数据类型

    官网数据类型介绍地址 https://redis.io/topics/data-types-intro

    官网有 8 种,前面 5 种为常用数据结构

    • string 二进制安全的字符串
    • Lists: 按插入顺序排序的字符串元素的集合。他们基本上就是链表(linked lists)
    • Sets: 不重复且无序的字符串元素的集合。
    • Sorted sets,类似Sets,但是每个字符串元素都关联到一个叫score浮动数值(floating number value)。里面的元素总是通过score进行着排序,所以不同的是,它是可以检索的一系列元素。(例如你可能会问:给我前面10个或者后面10个元素)。
    • Hashes,由field和关联的value组成的map。field和value都是字符串的。这和Ruby、Python的hashes很像。
    • Bit arrays (或者说 simply bitmaps): 通过特殊的命令,你可以将 String 值当作一系列 bits 处理:可以设置和清除单独的 bits,数出所有设为 1 的 bits 的数量,找到最前的被设为 1 或 0 的 bit,等等。
    • HyperLogLogs: 这是被用于估计一个 set 中元素数量的概率性的数据结构。
    • Streams:5.0版本新增, append-only collections of map-like entries that provide an abstract log data type.
      • 可以用来做持久化的消息队列

    4.1 String 字符串

    存储原理

    假设存储 key = hello vlaue = word

    set hello word
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkaWlhrs-1579594343660)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120115354305.png)]

    String的三种编码

    • int,存储8个字节的长整型(long,2^63-1)
    • embstr,embstr格式的SDS(Simple Dynamic String)
    • raw,SDS,存储大于44个字节的字符串

    redis 为什么要自己写一个SDS的数据类型

    主要是为了解决C语言 char[] 的四个问题

    1. 字符数组必须先给目标变量分配足够的空间,否则可能会溢出
    2. 查询字符数组长度 时间复杂度O(n)
    3. 长度变化,需要重新分配内存
    4. 通过从字符串开始到结尾碰到的第一个\0来标记字符串的结束,因此不能保存图片、音频、视频、压缩文件等二进制(bytes)保存的内容,二进制不安全

    redis SDS

    1. 不用担心内存溢出问题,如果需要会对 SDS 进行扩容
    2. 因为定义了 len 属性,查询数组长度时间复杂度O(1) 固定长度
    3. 空间预分配,惰性空间释放
    4. 根据长度 len来判断是结束,而不是 \0

    embstr和raw

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-98KQgtzI-1579594343660)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120144602150.png)]

    • 当 value 的值为整型时,编码为 int
    • 当 value 值为字符时,存储的编码为 embstr,连续的内存空间,只需要分配一次
    • 当 value 值字符长度超过 44 时,存储的编码为 raw,不是连续的内存空间,需要分配两次
    • 如果 value 的值为 int 或者 embstr ,然后通过 append 添加字符的时候,也会转化为 raw 类型(因为 embstr 设计的是只读的,如果发生变化只能再开辟一块空间),而且这个过程是不可逆的。

    应用场景

    • 缓存,热点数据
    • 分布式session
    • set key value NX EX 分布式锁
    • INCR计数器
      • 文章的阅读量,微博点赞数,允许一定的延迟,先写入 Redis 再定时同步到数据库
    • 全局ID
      • INT 类型,INCRBY,利用原子性
    • INCR 限流
      • 以访问者的 IP 和其他信息作为 key,访问一次增加一次计数,超过次数则返回 false。
    • setbit 位操作

    4.2 Hash 哈希

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P08IOaaL-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120162911742.png)]

    对于这种类似于数据库表的结构,redis中可以使用hash进行存储

    批量设置

     hmset coder:xwf age 30 addr wuhan tag java
    

    批量获取

     hmget coder:xwf age addr tag
    

    执行效果:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HV3H4be0-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120163552719.png)]

    **同样是存储字符串,Hash 与 String 的主要区别? **

    1、把所有相关的值聚集到一个 key 中,节省内存空间

    2、只使用一个 key,减少 key 冲突

    3、当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU 的消耗

    Hash 不适合的场景:

    1、Field 不能单独设置过期时间

    2、没有 bit 操作

    3、需要考虑数据量分布的问题(value 值非常大的时候,无法分布到多个节点)

    hash表有两种存储的数据编码

    如果Field的个数超过 512 个 或者 Field 中任意一个 键或者值 的长度大于 64个字节,hash表会用ht来存储

    redis配置文件

    hash-max-ziplist-entries 512
    hash-max-ziplist-value 64
    

    ziplist 压缩列表

    ziplist 是一个经过特殊编码的双向链表,它不存储指向上一个链表节点和指向下一 个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能, 来换取高效的内存空间利用率,是一种时间换空间的思想。只用在字段个数少,字段值小的场景里面
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mS2sFKm-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120165318390.png)]

    ht(hashtable) 哈希表

    在 Redis 中,hashtable 被称为字典(dictionary),它是一个数组+链表的结构。

    为什么有 ht[0] 和 ht[1] 两个hash表,是为了扩容。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFDCxy29-1579594343662)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120192718161.png)]

    应用场景

    购物车
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3qoFn7w-1579594343662)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120184047773.png)]

    存储 命令
    用户id key
    商品id field1
    商品数量 value1
    商品价格 field2
    商品价格值 value2
    操作 命令
    商品+1 hincr
    商品-1 hdecr
    删除 hdel
    全选 hgetall
    商品数量 hlen

    4.3 List 列表

    有序,左边是列表头,从左到右

    存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O5aYoeT2-1579594343663)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120190102111.png)]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9JoHrOm-1579594343663)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200121160924862.png)]

    127.0.0.1:6379> lpush queue a
    (integer) 1
    127.0.0.1:6379> lpush queue b c
    (integer) 3
    127.0.0.1:6379> lrange queue 0 -1
    1) "c"
    2) "b"
    3) "a"
    127.0.0.1:6379> rpush queue d e
    (integer) 5
    127.0.0.1:6379> lrange queue 0 -1
    1) "c"
    2) "b"
    3) "a"
    4) "d"
    5) "e"
    127.0.0.1:6379> lpop queue
    "c"
    127.0.0.1:6379> lrange queue 0 -1
    1) "b"
    2) "a"
    3) "d"
    4) "e"
    127.0.0.1:6379> rpop queue
    "e"
    127.0.0.1:6379> lrange queue 0 -1
    1) "b"
    2) "a"
    3) "d"
    

    List 存储原理(quicklist)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KaH2a3M6-1579594343664)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120185909116.png)]
    内部是一个双向链表,*zl 指针指向的是 ziplist 压缩列表,数据真正还是存储在 ziplist 中。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TChTwnro-1579594343664)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120191151179.png)]

    应用场景

    • 时间线
    • 队列

    4.4 Set 集合

    一个 set 集合可以存储 2^63-1 个元素

    127.0.0.1:6379> sadd xwfset 123 a b c d e f g 456
    (integer) 9
    127.0.0.1:6379> smembers xwfset
    1) "e"
    2) "f"
    3) "b"
    4) "d"
    5) "g"
    6) "123"
    7) "a"
    8) "c"
    9) "456"
    

    存储结构

    • intset
    • hashtable
    127.0.0.1:6379> object encoding xwfset
    "hashtable"
    127.0.0.1:6379> sadd intsets 1 2 3
    (integer) 3
    127.0.0.1:6379> object encoding intsets
    "intset"
    

    应用场景

    1.知乎点赞数
    在这里插入图片描述
    2.京东的商品筛选
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UWFCFsm-1579594343665)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120194833288.png)]

    127.0.0.1:6379> sadd brand:apple iPhone11
    (integer) 1
    127.0.0.1:6379> sadd brand:ios iPhone11
    (integer) 1
    127.0.0.1:6379> sadd screensize:6.0-6.24 iPhone11
    (integer) 1
    127.0.0.1:6379> sadd memorysize:256GB iPhone11
    (integer) 1
    127.0.0.1:6379> sinter brand:apple brand:ios screensize:6.0-6.24 memorysize:256GB
    1) "iPhone11"
    

    筛选商品,苹果,IOS,屏幕6.0-6.24,内存大小256G

    sinter brand:apple brand:ios screensize:6.0-6.24 memorysize:256GB

    3.微博关注

    用户(编号user001)关注

    sadd focus:user001 user003

    sadd focus:user002 user003 user004

    相互关注

    sadd focus:user001 user002

    sadd focus:user002 user001

    #判断用户2是否关注了用户1
    127.0.0.1:6379> SISMEMBER focus:user002 user001
    (integer) 1
    

    我关注得到人也关注了他(共同关注)

    #获取关注的交集
    127.0.0.1:6379> sinter focus:user001 focus:user002
    1) "user003"
    

    可能认识的人

    #将所有的人存放到allusers集合
    127.0.0.1:6379> SUNIONSTORE alluser:user001 focus:user001 focus:user002
    (integer) 4
    127.0.0.1:6379> SDIFF alluser:user001 focus:user001
    1) "user004"
    2) "user001"
    #剔除掉自己
    127.0.0.1:6379> SREM alluser:user001 user001
    (integer) 1
    127.0.0.1:6379> SDIFF alluser:user001 focus:user001
    1) "user004"
    

    4.5 ZSet 有序集合

    每个元素有一个对应的分数,基于分数进行排序;如果分数相等,以key值的 ascii 值进行排序。

    数据结构对比

    数据结构 是否允许重复元素 是否有序 有序实现方式
    list 索引下标
    set
    zset 分值score

    存储结构

    • ziplist

    • skiplist+dict 跳表+字典

    redis配置文件

    如果元素的个数超过 128 个 或者 元素中任意一个 value 的大小超过 64个字节,存储会采用 skiplist 跳表

    zset-max-ziplist-entries 128
    zset-max-ziplist-value 64
    

    什么是 skiplist ?

    上面的是普通的链表,下面的是跳表,level 是随机的

    普通链表查找一个元素的时间复杂度为O(n)

    跳表的时间复杂度为O(m*log2n)
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPDRBP4F-1579594343666)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200121103942711.png)]
    假设我们找元素19

    1.先从起始的 level3 指针中查找 26 大于 19

    2.退回到起始的 level2 的指针,大于7 继续往后,找到19

    3.通过三次就找到了19

    简书的一篇文章:redis用到的非常高效的数据结构–跳表

    应用场景

    1.商品的评价标签,可以记录商品的标签,统计标签次数,增加标签次数,按标签的分值进行排序
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-97TPeJgR-1579594343666)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120195514557.png)]

    #添加商品(编号i5001)的标签tag和对应标签的评价次数
    127.0.0.1:6379> zadd good_tag:i5001 442 tag1 265 tag2 264 tag3
    (integer) 3
    #不带分数
    127.0.0.1:6379> zrange good_tag:i5001 0 -1
    1) "tag3"
    2) "tag2"
    3) "tag1"
    #带分数
    127.0.0.1:6379> zrange good_tag:i5001 0 -1 withscores
    1) "tag3"
    2) "264"
    3) "tag2"
    4) "265"
    5) "tag1"
    6) "442"
    

    2.百度搜索热点
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJv8D7rq-1579594343667)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120202817364.png)]

    #维护2020年1月21号的热点新闻
    127.0.0.1:6379> zadd hotspot:20200121 520 pot1 263 pot2 244 pot3
    (integer) 3
    127.0.0.1:6379> zrange hotspot:20200121 0 -1 withscores
    1) "pot3"
    2) "244"
    3) "pot2"
    4) "263"
    5) "pot1"
    6) "520"
    #增加点击次数
    127.0.0.1:6379> ZINCRBY hotspot 1 pot1
    "521"
    

    4.6 BitMaps

    Bitmaps 是在字符串类型上面定义的位操作。一个字节由 8 个二进制位组成。

    应用场景:

    用户访问统计

    在线用户统计

    4.7 Hyperloglogs

    Hyperloglogs:提供了一种不太准确的基数统计方法,比如统计网站的 UV,存在一定的误差。

    4.8 Streams

    5.0 推出的数据类型。支持多播的可持久化的消息队列,用于实现发布订阅功能,借鉴了 kafka 的设计。

    5.总结

    数据结构

    对象 对象type属性值 type命令输出 object encoding
    字符串 OBJ_STRING “string” int/embstr/raw
    列表 OBJ_LIST “list” quicklist
    哈希 OBJ_HASH “hash” ziplist/hashtable
    集合 OBJ_SET “set” intset/hashtable
    有序集合 OBJ_ZSET “zset” ziplist/skiplist

    编码转换

    对象 元素编码 升级编码 再次升级
    字符串 INT 整数并且小于 log 2^63-1 embstr 超过44字节被修改 raw
    哈希 ziplist 键和值的长度小于64字节,键值对个数不超过521个 hashtable
    列表 quicklist
    集合 intset 元素都是整数,元素个数小于512 hashtable
    有序集合 ziplist 任何一个member长度小于64字节,元素个数不超过128个 skiplist

    6.参考

    咕泡学院 青山老师 redis-基础篇(原版更加具体,对照redis的源码进行讲解)

    展开全文
  • NoSQL 开发中或多或少都会用到,也是面试必问知识点。最近这几天的面试每一场都问到了。...Redis 系列:1、Redis 的五大数据类型Redis-key127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379> set n...

    NoSQL 开发中或多或少都会用到,也是面试必问知识点。最近这几天的面试每一场都问到了。但是感觉回答的并不好,还有很多需要梳理的知识点。这里通过几篇 Redis 笔记整个梳理一遍,后面再加上面试题。

    Redis 系列:

    1、Redis 的五大数据类型

    Redis-key

    127.0.0.1:6379> keys *

    (empty list or set)

    127.0.0.1:6379> set name xxx

    OK

    127.0.0.1:6379> keys *

    1) "name"

    127.0.0.1:6379> set age 1

    OK

    127.0.0.1:6379> keys *

    1) "age"

    2) "name"

    127.0.0.1:6379> exists name# 判断key 是否存在

    (integer) 1

    127.0.0.1:6379> exists name1

    (integer) 0

    127.0.0.1:6379> move name 1

    (integer) 1

    127.0.0.1:6379> keys *

    1) "age"

    127.0.0.1:6379> set name yyy

    OK

    127.0.0.1:6379> expire name 10 # 设置key的过期时间,单位是秒

    (integer) 1

    127.0.0.1:6379> ttl name# 查看当前key的剩余过期时间

    (integer) 7

    127.0.0.1:6379> ttl name

    (integer) -2

    127.0.0.1:6379> type age# 查看当前key的类型

    string

    127.0.0.1:6379>

    Redis 有以下 5 种基本的数据类型

    1、String(字符串)

    127.0.0.1:6379> set key1 v1#设置值

    OK

    127.0.0.1:6379> get key1

    "v1"

    127.0.0.1:6379> append key1 "hello"# 追加值,如果不存在,相当于 set key

    (integer) 7

    127.0.0.1:6379> get key1

    "v1hello"

    127.0.0.1:6379> strlen key1# 获取字符串长度

    (integer) 7

    127.0.0.1:6379>

    自增、自减

    127.0.0.1:6379> set views 0

    OK

    127.0.0.1:6379> get views

    "0"

    127.0.0.1:6379> incr views# 自增 1

    (integer) 1

    127.0.0.1:6379> get views

    "1"

    127.0.0.1:6379> decr views # 自减 1

    (integer) 0

    127.0.0.1:6379> decr views

    (integer) -1

    127.0.0.1:6379> get views

    "-1"

    127.0.0.1:6379> incrby views 10# 设置步长、自增 10

    (integer) 9

    127.0.0.1:6379> decrby views 5 # 设置步长、自减 5

    (integer) 4

    字符串范围

    127.0.0.1:6379> set key1 "hello,world!"

    OK

    127.0.0.1:6379> get key1

    "hello,world!"

    127.0.0.1:6379> getrange key1 0 3# 截取字符串[0, 3]

    "hell"

    127.0.0.1:6379> getrange key1 0 -1# 获取全部的字符串,和 get key一样

    "hello,world!"

    127.0.0.1:6379>

    替换:

    127.0.0.1:6379> set key2 abcdefg

    OK

    127.0.0.1:6379> get key2

    "abcdefg"

    127.0.0.1:6379> setrange key2 1 xx

    (integer) 7

    127.0.0.1:6379> get key2

    "axxdefg"

    127.0.0.1:6379>

    setex(set with expire):设置过期时间

    和setnx(set if not exist):不存在再设置(在分布式锁中会经常使用)

    127.0.0.1:6379> setex key3 30 "hello"# 设置 30 秒后过期

    OK

    127.0.0.1:6379> ttl key3# 剩余过期时间

    (integer) 25

    127.0.0.1:6379> setnx mykey "redis"# mykey 不存在时设置成功

    (integer) 1

    127.0.0.1:6379> keys *

    1) "key2"

    2) "key1"

    3) "views"

    4) "mykey"

    127.0.0.1:6379> setnx mykey "mongoDB"# mykey 存在时设置失败

    (integer) 0

    127.0.0.1:6379> get mykey# mykey 值不变

    "redis"

    127.0.0.1:6379>

    mset 和 mget

    127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3# 同时设置多个值

    OK

    127.0.0.1:6379> keys *

    1) "k1"

    2) "k3"

    3) "k2"

    127.0.0.1:6379> mget k1 k2 k3# 同时获取多个值

    1) "v1"

    2) "v2"

    3) "v3"

    127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作,要么一起成功,要么都失败

    (integer) 0

    127.0.0.1:6379> get k4

    (nil)

    127.0.0.1:6379>

    对象

    set user:1 {name:zhangsan, age:3} # 设置一个 user:1 对象 值为 json 字符来保存一个对象

    127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2

    OK

    127.0.0.1:6379> mget user:1:name user:1:age

    1) "zhangsan"

    2) "2"

    127.0.0.1:6379>

    getset:先 get 再 set

    127.0.0.1:6379> getset db redis# 如果不存在值,则返回 nil

    (nil)

    127.0.0.1:6379> get db

    "redis"

    127.0.0.1:6379> getset db mongodb# 如果存在值,获取原来的值,并设置新的值

    "redis"

    127.0.0.1:6379> get db

    "mongodb"

    127.0.0.1:6379>

    String 的使用场景:value 除了是字符串以外还可以是数字

    计数器

    统计多单位的数量

    粉丝数

    对象缓存存储

    2、List(列表)

    基本的数据类型,列表。

    在 Redis 中可以把 list 用作栈、队列、阻塞队列。

    list 命令多数以 l开头。

    127.0.0.1:6379> lpush list one# 将一个值或者多个值,插入到列表的头部(左)

    (integer) 1

    127.0.0.1:6379> lpush list two

    (integer) 2

    127.0.0.1:6379> lpush list three

    (integer) 3

    127.0.0.1:6379> lrange list 0 -1# 查看全部元素

    1) "three"

    2) "two"

    3) "one"

    127.0.0.1:6379> lrange list 0 1# 通过区间获取值

    1) "three"

    2) "two"

    127.0.0.1:6379> rpush list right# 将一个值或者多个值,插入到列表的尾部(右)

    (integer) 4

    127.0.0.1:6379> lrange list 0 -1

    1) "three"

    2) "two"

    3) "one"

    4) "right"

    127.0.0.1:6379>

    弹出 pop

    127.0.0.1:6379> lrange list 0 -1

    1) "!"

    2) "world"

    3) "world"

    4) "hello"

    127.0.0.1:6379> lpop list# 移除list的第一个元素

    "!"

    127.0.0.1:6379> lrange list 0 -1

    1) "world"

    2) "world"

    3) "hello"

    127.0.0.1:6379> rpop list# 移除list的第一个元素

    "hello"

    127.0.0.1:6379> lrange list 0 -1

    1) "world"

    2) "world"

    127.0.0.1:6379>

    索引 Lindex

    127.0.0.1:6379> lrange list 0 -1

    1) "hjk"

    2) "world"

    3) "world"

    127.0.0.1:6379> lindex list 1# 通过下标获取list中的某一个值

    "world"

    127.0.0.1:6379> lindex list 0

    "hjk"

    127.0.0.1:6379>

    Llen 长度:

    127.0.0.1:6379> llen list

    (integer) 3

    127.0.0.1:6379>

    移除指定的值:

    127.0.0.1:6379> lrange list 0 -1

    1) "hjk"

    2) "world"

    3) "world"

    127.0.0.1:6379> lrem list 1 world# 移除list集合中指定个数的value,精确匹配

    (integer) 1

    127.0.0.1:6379> lrange list 0 -1

    1) "hjk"

    2) "world"

    127.0.0.1:6379> lpush list hjk

    (integer) 3

    127.0.0.1:6379> lrange list 0 -1

    1) "hjk"

    2) "hjk"

    3) "world"

    127.0.0.1:6379> lrem list 2 hjk

    (integer) 2

    127.0.0.1:6379> lrange list 0 -1

    1) "world"

    127.0.0.1:6379>

    trim 截断

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello1"

    2) "hello2"

    3) "hello3"

    4) "hello4"

    127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定长度,这个list已经被破坏了,截断之后只剩下截断后的元素

    OK

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello2"

    2) "hello3"

    127.0.0.1:6379>

    rpoplpush :移除列表的最后一个元素,将他移动到新的列表中。

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello1"

    2) "hello2"

    3) "hello3"

    127.0.0.1:6379> rpoplpush mylist myotherlist# 移除列表的最后一个元素,将他移动到新的列表中。

    "hello3"

    127.0.0.1:6379> lrange mylist 0 -1# 查看原来的列表

    1) "hello1"

    2) "hello2"

    127.0.0.1:6379> lrange myotherlist 0 -1# 查看目标列表中,确实存在该值

    1) "hello3"

    127.0.0.1:6379>

    lset:将列表中指定下标的值替换为另一个值,更新操作

    127.0.0.1:6379> exists list# 判断这个列表是否存在

    (integer) 0

    127.0.0.1:6379> lset list 0 item# 如果不存在的话,更新会报错

    (error) ERR no such key

    127.0.0.1:6379> lpush list value1

    (integer) 1

    127.0.0.1:6379> lrange list 0 0

    1) "value1"

    127.0.0.1:6379> lset list 0 item# 如果存在,更新当前下标的值

    OK

    127.0.0.1:6379> lset list 1 other# 如果不存在的话,更新会报错

    (error) ERR index out of range

    127.0.0.1:6379>

    linsert:将某个具体的value插入到列表中某个元素的前面或者后面

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello1"

    2) "hello2"

    127.0.0.1:6379> linsert mylist before "hello2" hello

    (integer) 3

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello1"

    2) "hello"

    3) "hello2"

    127.0.0.1:6379> linsert mylist after "hello2" hello

    (integer) 4

    127.0.0.1:6379> lrange mylist 0 -1

    1) "hello1"

    2) "hello"

    3) "hello2"

    4) "hello"

    127.0.0.1:6379>

    小结:

    list 实际上是一个链表,前后都可以插入

    如果key不存在,创建新的链表

    如果移除了所有的值,空链表,也代表不存在

    在两边插入或者改动值,效率最高。

    3、Set (集合)

    127.0.0.1:6379> sadd myset "hello"# set 集合中添加元素

    (integer) 1

    127.0.0.1:6379> sadd myset "world"

    (integer) 1

    127.0.0.1:6379> smembers myset # 查看指定Set的所有值

    1) "world"

    2) "hello"

    127.0.0.1:6379> sismember myset hello# 判断某一个值是不是在set中

    (integer) 1

    127.0.0.1:6379> sismember myset hello1

    (integer) 0

    127.0.0.1:6379>

    127.0.0.1:6379> scard myset# 获取集合中的个数

    (integer) 2

    127.0.0.1:6379> sadd myset "hello2"

    (integer) 1

    127.0.0.1:6379> smembers myset

    1) "world"

    2) "hello2"

    3) "hello"

    127.0.0.1:6379> srem myset hello # 移除元素

    (integer) 1

    127.0.0.1:6379> smembers myset

    1) "world"

    2) "hello2"

    127.0.0.1:6379>

    127.0.0.1:6379> smembers myset

    1) "kkk"

    2) "world"

    3) "hjk"

    4) "hello2"

    127.0.0.1:6379> srandmember myset# 随机抽取一个元素

    "hjk"

    127.0.0.1:6379> srandmember myset

    "hello2"

    127.0.0.1:6379> srandmember myset 2# 随机抽取指定个数的元素

    1) "world"

    2) "hello2"

    127.0.0.1:6379> srandmember myset 2

    1) "hello2"

    2) "hjk"

    127.0.0.1:6379>

    127.0.0.1:6379> smembers myset

    1) "kkk"

    2) "world"

    3) "hjk"

    4) "hello2"

    127.0.0.1:6379> spop myset# 随机删除元素

    "hjk"

    127.0.0.1:6379> smembers myset

    1) "kkk"

    2) "world"

    3) "hello2"

    127.0.0.1:6379> spop myset

    "hello2"

    127.0.0.1:6379> smembers myset

    1) "kkk"

    2) "world"

    127.0.0.1:6379>

    127.0.0.1:6379> smembers myset

    1) "kkk"

    2) "world"

    127.0.0.1:6379> sadd myset2 set2

    (integer) 1

    127.0.0.1:6379> smove myset myset2 "kkk"# 将一个特定的值,移动到另一个set集合中

    (integer) 1

    127.0.0.1:6379> smembers myset

    1) "world"

    127.0.0.1:6379> smembers myset2

    1) "kkk"

    2) "set2"

    127.0.0.1:6379>

    127.0.0.1:6379> smembers key1

    1) "b"

    2) "a"

    3) "c"

    127.0.0.1:6379> smembers key2

    1) "e"

    2) "d"

    3) "c"

    127.0.0.1:6379> sdiff key1 key2# 差集

    1) "b"

    2) "a"

    127.0.0.1:6379> sinter key1 key2 # 交集

    1) "c"

    127.0.0.1:6379> sunion key1 key2# 并集

    1) "e"

    2) "a"

    3) "c"

    4) "d"

    5) "b"

    4、Hash(哈希)

    也是 key - value 形式的,但是value 是一个map。

    127.0.0.1:6379> hset myhash field xxx# set 一个 key-value

    (integer) 1

    127.0.0.1:6379> hget myhash field# 获取一个字段值

    "xxx"

    127.0.0.1:6379> hmset myhash field1 hello field2 world# set 多个 key-value

    OK

    127.0.0.1:6379> hmget myhash field field1 field2# 获取多个字段值

    1) "xxx"

    2) "hello"

    3) "world"

    127.0.0.1:6379> hgetall myhash# 获取全部的数据

    1) "field"

    2) "xxx"

    3) "field1"

    4) "hello"

    5) "field2"

    6) "world"

    127.0.0.1:6379> hdel myhash field1# 删除指定的key,对应的value也就没有了

    (integer) 1

    127.0.0.1:6379> hgetall myhash

    1) "field"

    2) "xxx"

    3) "field2"

    4) "world"

    127.0.0.1:6379>

    127.0.0.1:6379> hlen myhash# 获取长度

    (integer) 2

    127.0.0.1:6379> hexists myhash field1 # 判断指定key是否存在

    (integer) 0

    127.0.0.1:6379> hexists myhash field2

    (integer) 1

    127.0.0.1:6379> hkeys myhash# 获取所有的key

    1) "field"

    2) "field2"

    127.0.0.1:6379> hvals myhash# 获取所有的value

    1) "xxx"

    2) "world"

    127.0.0.1:6379>

    127.0.0.1:6379> hset myhash field3 5

    (integer) 1

    127.0.0.1:6379> hincrby myhash field3 1# 指定增量

    (integer) 6

    127.0.0.1:6379> hincrby myhash field3 -1

    (integer) 5

    127.0.0.1:6379> hsetnx myhash field4 hello# 如果不存在则可以设置

    (integer) 1

    127.0.0.1:6379> hsetnx myhash field4 world# 如果存在则不能设置

    (integer) 0

    127.0.0.1:6379>

    Hash 适合存储经常变动的对象信息,String 更适合于存储字符串。

    5、zset (有序集合)

    127.0.0.1:6379> zadd myset 1 one# 添加一个值

    (integer) 1

    127.0.0.1:6379> zadd myset 2 two 3 three# 添加多个值

    (integer) 2

    127.0.0.1:6379> zrange myset 0 -1

    1) "one"

    2) "two"

    3) "three"

    127.0.0.1:6379>

    实现排序:

    127.0.0.1:6379> zadd salary 2500 xiaohong

    (integer) 1

    127.0.0.1:6379> zadd salary 5000 xiaoming

    (integer) 1

    127.0.0.1:6379> zadd salary 500 xaiozhang

    (integer) 1

    127.0.0.1:6379> zrange salary 0 -1

    1) "xaiozhang"

    2) "xiaohong"

    3) "xiaoming"

    127.0.0.1:6379> zrangebyscore salary -inf +inf# 从小到大显示全部的用户

    1) "xaiozhang"

    2) "xiaohong"

    3) "xiaoming"

    127.0.0.1:6379> zrevrange salary 0 -1# 从大到小进行排序

    1) "xiaoming"

    2) "xiaohong"

    3) "xaiozhang"

    127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 附带成绩的显示所有用户

    1) "xaiozhang"

    2) "500"

    3) "xiaohong"

    4) "2500"

    5) "xiaoming"

    6) "5000"

    127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores# 显示工资小于 2500 的用户

    1) "xaiozhang"

    2) "500"

    3) "xiaohong"

    4) "2500"

    127.0.0.1:6379> zrange salary 0 -1

    1) "xaiozhang"

    2) "xiaohong"

    3) "xiaoming"

    127.0.0.1:6379> zrem salary xiaohong # 移除特定元素

    (integer) 1

    127.0.0.1:6379> zrange salary 0 -1

    1) "xaiozhang"

    2) "xiaoming"

    127.0.0.1:6379> zcard salary# 获取有序集合的个数

    (integer) 2

    127.0.0.1:6379>

    127.0.0.1:6379> zadd myset 1 hello

    (integer) 1

    127.0.0.1:6379> zadd myset 2 world 3 !

    (integer) 2

    127.0.0.1:6379> zcount myset 1 3# 获取指定区间的人员数量

    (integer) 3

    127.0.0.1:6379> zcount myset 1 2

    (integer) 2

    2、Redis 三种特殊数据类型

    1、geospatial

    Redis 在 3.2 推出 Geo 类型,该功能可以推算出地理位置信息,两地之间的距离。

    geoadd 添加地理位置

    规则:两极无法直接添加,一般会下载城市数据,直接通过 Java 程序一次性导入。

    有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。当坐标位置超出指定范围时,该命令将会返回一个错误。

    (error) ERR invalid longitude latitude pair xxx yyy

    添加一些模拟数据:

    127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing

    (integer) 1

    127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai

    (integer) 1

    127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shengzhen

    (integer) 2

    127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian

    (integer) 2

    127.0.0.1:6379>

    geopos 获得当前定位坐标值

    127.0.0.1:6379> geopos china:city beijing# 获得指定城市的经纬度

    1) 1) "116.39999896287918091"

    2) "39.90000009167092543"

    127.0.0.1:6379> geopos china:city shanghai

    1) 1) "121.47000163793563843"

    2) "31.22999903975783553"

    127.0.0.1:6379>

    geodist 获取两个位置之间的距离

    单位:

    m 表示单位为米。

    km 表示单位为千米。

    mi 表示单位为英里。

    ft 表示单位为英尺。

    如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

    127.0.0.1:6379> geodist china:city beijing shanghai km# 查看北京和上海直接的直线距离

    "1067.3788"

    127.0.0.1:6379> geodist china:city beijing chongqing km

    "1464.0708"

    127.0.0.1:6379>

    georedius 以给定的经纬度为中心,找出某一半径内的元素

    127.0.0.1:6379> georadius china:city 110 30 1000 km # 以110, 30 这个点为中心,寻找方圆 1000km 的城市

    1) "chongqing"

    2) "xian"

    3) "shengzhen"

    4) "hangzhou"

    127.0.0.1:6379> georadius china:city 110 30 500 km

    1) "chongqing"

    2) "xian"

    127.0.0.1:6379> georadius china:city 110 30 500 km withcoord# 显示他人的定位信息

    1) 1) "chongqing"

    2) 1) "106.49999767541885376"

    2) "29.52999957900659211"

    2) 1) "xian"

    2) 1) "108.96000176668167114"

    2) "34.25999964418929977"

    127.0.0.1:6379>

    127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 显示到中心点的距离

    1) 1) "chongqing"

    2) "341.9374"

    2) 1) "xian"

    2) "483.8340"

    127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 1 # 指定数量

    1) 1) "chongqing"

    2) "341.9374"

    3) 1) "106.49999767541885376"

    2) "29.52999957900659211"

    127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 2

    1) 1) "chongqing"

    2) "341.9374"

    3) 1) "106.49999767541885376"

    2) "29.52999957900659211"

    2) 1) "xian"

    2) "483.8340"

    3) 1) "108.96000176668167114"

    2) "34.25999964418929977"

    127.0.0.1:6379>

    GEORADIUSBYMEMBER 找出位于指定元素周围的其他元素

    127.0.0.1:6379> georadiusbymember china:city shanghai 1000 km

    1) "hangzhou"

    2) "shanghai"

    127.0.0.1:6379>

    geo 底层实现原理其实就是 zset ,可以使用 zset 命令操作 geo

    127.0.0.1:6379> zrange china:city 0 -1

    1) "chongqing"

    2) "xian"

    3) "shengzhen"

    4) "hangzhou"

    5) "shanghai"

    6) "beijing"

    127.0.0.1:6379> zrem china:city beijing# 删除一个元素

    (integer) 1

    127.0.0.1:6379> zrange china:city 0 -1

    1) "chongqing"

    2) "xian"

    3) "shengzhen"

    4) "hangzhou"

    5) "shanghai"

    127.0.0.1:6379>

    2、hyperloglog

    基数:数学上集合的元素个数,是不能重复的。

    UV(Unique visitor):是指通过互联网访问、浏览这个网页的自然人。访问的一个电脑客户端为一个访客,一天内同一个访客仅被计算一次。

    Redis 2.8.9 版本更新了 hyperloglog 数据结构,是基于基数统计的算法。

    hyperloglog 的优点是占用内存小,并且是固定的。存储 2^64 个不同元素的基数,只需要 12 KB 的空间。但是也可能有 0.81% 的错误率。

    这个数据结构常用于统计网站的 UV。传统的方式是使用 set 保存用户的ID,然后统计 set 中元素的数量作为判断标准。但是这种方式保存了大量的用户 ID,ID 一般比较长,占空间,还很麻烦。我们的目的是计数,不是保存数据,所以这样做有弊端。但是如果使用 hyperloglog 就比较合适了。

    127.0.0.1:6379> pfadd mykey a b c d e f g h i j# 创建第一组元素

    (integer) 1

    127.0.0.1:6379> PFCOUNT mykey# 统计 mykey 基数

    (integer) 10

    127.0.0.1:6379> PFADD mykey2 i j z x c v b n m # 创建第二组元素

    (integer) 1

    127.0.0.1:6379> PFCOUNT mykey2# 统计 mykey2 基数

    (integer) 9

    127.0.0.1:6379> PFMERGE mykey3 mykey mykey2# 合并两组 mykey mykey2 => mykey3

    OK

    127.0.0.1:6379> PFCOUNT mykey3

    (integer) 15

    127.0.0.1:6379>

    3、bitmap 位图

    bitmap就是通过最小的单位bit来进行0或者1的设置,表示某个元素对应的值或者状态。一个bit的值,或者是0,或者是1;也就是说一个bit能存储的最多信息是2。

    bitmap 常用于统计用户信息比如活跃粉丝和不活跃粉丝、登录和未登录、是否打卡等。

    这里使用一周打卡的案例说明其用法:

    127.0.0.1:6379> setbit sign 0 1# 周一打卡了

    (integer) 0

    127.0.0.1:6379> setbit sign 1 0# 周二未打卡

    (integer) 0

    127.0.0.1:6379> setbit sign 2 0# 周三未打卡

    (integer) 0

    127.0.0.1:6379> setbit sign 3 1

    (integer) 0

    127.0.0.1:6379> setbit sign 4 1

    (integer) 0

    127.0.0.1:6379> setbit sign 5 1

    (integer) 0

    127.0.0.1:6379> setbit sign 6 0

    (integer) 0

    127.0.0.1:6379>

    查看某一天是否打卡:

    127.0.0.1:6379> GETBIT sign 3

    (integer) 1

    127.0.0.1:6379> GETBIT sign 6

    (integer) 0

    127.0.0.1:6379>

    统计:统计打卡的天数

    127.0.0.1:6379> BITCOUNT sign

    (integer) 4

    127.0.0.1:6379>

    展开全文
  • Redis对象类型简介 Redis共有五种对象的类型,分别是: ...底层数据结构共有八种,如下表所示: 编码常量 编码所对应的底层数据结构 REDIS_ENCODING_INT long 类型的整数 REDIS_ENCODING_EMBSTR
  • 推荐阅读:互联网公司面试必问的Redis...基本上,一个合格的程序员,五种类型都会用到。回答一共五(一)String这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能...
  • Redis
  • Redis数据类型

    2020-12-22 14:04:45
    Redis 有以下 8 种数据类型: 第一种:String (字符串) 第二种:List(列表) 第三种、Set (集合) 第四种、Hash(哈希) 第五种:zset (有序集合) 第六种:geospatial 第七种:hyperloglog 第八种:bitmap 位图 ...
  • Redis的数据类型以及每种数据类型的使用场景 原文:Redis的数据类型以及每种数据类型的使用场景人就是很奇怪的动物,很简单的问题往往大家都容易忽略,当我们在使用分布式缓存Redis的时候,一个最简单...
  • 特殊数据类型 geospatial hyperloglog bitmap 基础知识 操作大全:http://www.redis.cn/commands.html redis不区分大小写命令 select 7 # redis有16个数据库(0-15),默认使用第0个,可用select切换...
  • 文末附带这八种数据类型的思维导图。 String String是Redis最基本的数据结构,他采用K-V的形式来存储数据,当然了,虽然是String,但是他的value也可以为int、float形式,也可以存储json、图片等,但是不能超过521MB...
  • Redis数据类型

    2019-07-27 14:42:55
      Redis支持字符串、哈希表、列表、集合、有序集合、位图、地理位置和HyperLogLog这八种数据类型Redis的所有数据结构都以唯一的key字符串作为名称,然后通过这个唯一的key值获取相应的value数据。不同类型的数据...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 124
精华内容 49
关键字:

redis八种数据类型

redis 订阅