咱们知道Redis是目前很是主流的KV数据库,它因高性能的读写能力而著称,其实还有另一个优点,就是Redis提供了更加丰富的数据类型,这使得Redis有着更加普遍的使用场景。那Redis提供给用户的有哪些数据类型呢?主要有:string(字符串)、List(列表)、Set(集合)、Hash(哈希)、Zset(有序集合)、HyperLogLogs(计算基数用的一种数据结构)、Streams(Redis 5.0提供一种建模日志用的全新数据结构)。java
须要注意的是这里说的数据类型是指Redis值的数据类型,而Redis键的类型老是string。mysql
本文主要详解一下前5种,也就是最经常使用的5种数据类型。剩下两种可上Redis官网(redis.io)自行了解下。另外,Redis已是目前Java程序员面试必问内容,而 “Redis有哪些数据类型?”
更是面试官张口就来的基础问题。若是连这第一问都过不了,那基本上Redis这块已经凉凉了。程序员
redis的字符串类型,能够存储字符串、整数或者浮点数。若是存储的是整数或者浮点数,还能执行自增或者自减操做。面试
而且redis的string类型是二进制安全的,它能够包含任何数据,好比一个序列化的对象、一个图片字节流等。不过存储大小是由上限的-512Mredis
这里解释下二进制安全的含义:简单的来讲,就是字符串不是根据某种特殊的标志位来(C语言的\0)解析的,不管输入的是什么,总能保证输出是处理的原始输入而不是根据某种特殊格式来处理。spring
答案是Sds (Simple Dynamic String,简单动态字符串),Redis底层定义了本身的一种数据结构。(简单了解下)sql
typedef char *sds; struct sdshdr { // buf 已占用长度 int len; // buf 剩余可用长度 int free; // 实际保存字符串数据的地方 char buf[]; };
基础set、get、del命令及示例数据库
get keyname
获取存储在给定键中的值
set keyname value
设置存储唉给定键中的值
del keyname
删除存储在给定键中的值(通用命令,适用于全部类型)安全
127.0.0.1:6379> set happy today OK 127.0.0.1:6379> get happy "today" 127.0.0.1:6379> del happy (integer) 1 127.0.0.1:6379> get happy (nil) 127.0.0.1:6379>
自增和自减命令springboot
incr keyname
将键存储的值加1
decr kename
将键存储的是减1
incrby keyname amount
将键存储的值加上整数amount
decrby keyname amount
将键存储的值减去整数amount
incrbyfloat keyname amount
将键存储的值加上浮点数amount
127.0.0.1:6379> set number 1 OK 127.0.0.1:6379> get number "1" 127.0.0.1:6379> incr number (integer) 2 127.0.0.1:6379> get number "2" 127.0.0.1:6379> decr number (integer) 1 127.0.0.1:6379> get number "1" 127.0.0.1:6379> incrby number 3 (integer) 4 127.0.0.1:6379> get number "4" 127.0.0.1:6379> decrby number 2 (integer) 2 127.0.0.1:6379> get number "2" 127.0.0.1:6379> incrbyfloat number 1.23 "3.23" 127.0.0.1:6379> get number "3.23"
子串和二进制位命令
append keyname value
追加value值到指定字符串末尾
getrange keyname start end
获取start到end范围的全部字符组成的子串,包括start和end在内
setrange keyname offset value
从偏移量 offset 开始, 用 value 参数覆写(overwrite)键 keyname 储存的字符串值。
getbit keyname offset
对 keyname 所储存的字符串值,获取指定偏移量上的位(bit)。
setbit keyname offset value
对 keyname 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
注意redis的索引以0为开始
127.0.0.1:6379> get hello "world" 127.0.0.1:6379> append hello ,java (integer) 10 127.0.0.1:6379> get hello "world,java" 127.0.0.1:6379> getrange hello 2 5 "rld," 127.0.0.1:6379> setrange hello 6 redis (integer) 11 127.0.0.1:6379> get hello "world,redis" 127.0.0.1:6379> 127.0.0.1:6379> setbit bitstr 100 1 (integer) 0 127.0.0.1:6379> getbit bitstr 100 (integer) 1 127.0.0.1:6379> get bitstr "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b" 127.0.0.1:6379>
其余几个重要的命令
setnx key value
只在键 key 不存在的状况下, 将键 key 的值设置为 value;若键 key 已经存在, 则 SETNX 命令不作任何动做。
setex key seconds value
将键 key 的值设置为 value , 并将键 key 的生存时间设置为 seconds 秒钟。若是键 key 已经存在, 那么 SETEX 命令将覆盖已有的值。
说明一下:
127.0.0.1:6379> exists mark (integer) 0 127.0.0.1:6379> setnx mark abcd (integer) 1 127.0.0.1:6379> setnx mark defg (integer) 0 127.0.0.1:6379> get mark "abcd" 127.0.0.1:6379> setex cachekey 20 ak98 OK 127.0.0.1:6379> get cachekey "ak98" 127.0.0.1:6379> ttl cachekey (integer) 2
Redis的列表类型和许多程序语言中的列表类型相似,能够有序地存储多个字符串
。
支持从列表的左端和右端推入或弹出元素。Redis列表的底层实现是压缩列表(redis内容本身实现的数据结构)和双端链表。看下图
图片来自《Redis 设计与实现》
lpush key value [value...]
将一个或者多个value值插入列表的表头。若是 key 不存在,会建立一个空列表并执行 LPUSH 操做。当 key 存在但不是列表类型时,返回一个错误。
执行 LPUSH 命令后,会返回列表的长度。
127.0.0.1:6379> lpush listkey a (integer) 1 127.0.0.1:6379> lpush listkey a b c (integer) 4 127.0.0.1:6379> lrange listkey 0 -1 1) "c" 2) "b" 3) "a" 4) "a" 127.0.0.1:6379>
LPOP key
从列表的左端弹出一个值,并返回被弹出的值
127.0.0.1:6379> lrange listkey 0 -1 1) "c" 2) "b" 3) "a" 4) "a" 127.0.0.1:6379> lpop listkey "c" 127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379>
lrange key start end
获取列表key在给定start到end范围上的全部元素值。
0表示第一个元素,-1表示最后一个元素。
127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379> lrange listkey 0 1 1) "b" 2) "a" 127.0.0.1:6379>
lindex key index
获取列表在给定index位置上的单个元素值。
能够是-1,表明最后一个元素,-2表示倒数第二个元素,以此类推。
127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379> lindex listkey 0 "b" 127.0.0.1:6379> lindex listkey -1 "a" 127.0.0.1:6379> lindex listkey 3 (nil) 127.0.0.1:6379>
blpop key [key …] timeout
blpop 是阻塞式的弹出命令,它是lpop key 命令的阻塞版本。当给定列表内没有任何元素可供弹出的时候,链接将被 blpop 命令阻塞,直到等待超时或发现可弹出元素为止。
当给定多个 key 参数时,按参数 key 的前后顺序依次检查各个列表,弹出第一个非空列表的头元素。
所以能够分两种状况讨论,一种是至少有一个key存在且是非空列表,则blpop命令不会阻塞,另外是blpop命令中的列表是空列表,此时会在超时时间内阻塞。
先看下非阻塞的场景,返回值是第一个非空列表名和被弹出元素。
127.0.0.1:6379> lpush list1 hello java (integer) 2 127.0.0.1:6379> lpush list2 hello redis (integer) 2 127.0.0.1:6379> blpop list2 list1 list3 0 1) "list2" 2) "redis" 127.0.0.1:6379>
阻塞的场景,在执行了blpop book1 book2 300 命令后会一直阻塞住。
127.0.0.1:6379> exists book1 (integer) 0 127.0.0.1:6379> exists book2 (integer) 0 127.0.0.1:6379> blpop book1 book2 300 阻塞在这里了
这个时候,咱们若是在开另一个redis客户端,执行以下lpush
命令往book1列表中推入一个元素。
127.0.0.1:6379> lpush book1 springboot (integer) 1 127.0.0.1:6379>
此时,再回到原来阻塞的客户端,已经弹出了元素。
127.0.0.1:6379> exists book1 (integer) 0 127.0.0.1:6379> exists book2 (integer) 0 127.0.0.1:6379> blpop book1 book2 300 1) "book1" 2) "springboot" (237.45s) 127.0.0.1:6379>
经过利用Redis列表类型的阻塞式命令的特性,咱们最容易想到的就是能够用它实现一个简易版的消息队列。
Redis的集合以无序的方式存储多个不一样的元素。这里要注意的是无序和不一样。
除了对集合能快速执行添加、删除、检查一个元素是否在集合中以外,还能够对多个集合执行交集、并集和差集运算。
Redis的集合类型底层实现主要是经过一种叫作字典的数据结构。不过Redis为了追求极致的性能,会根据存储的值是不是整数,选择一种intset的数据结构。当知足必定条件后,会切换成字典的实现。
这里大概解释下字典
: 实际上是由一集键值对(key-value pairs)组成, 各个键值对的键各不相同, 程序能够添加新的键值对到字典中, 或者基于键进行查找、更新或删除等操做。
Redis的set(集合)在使用字典数据结构保存数据时,将元素保存到字典的键里面, 而字典的值则统一设为 NULL 。
sadd key member [member...]
将一个或者多个元素添加到集合key中,已存在于集合中的元素将被忽略。返回新添加的元素数量,不包括忽略的元素。
srem key member [member...]
移除集合中的一个或多个元素,不存在的元素将被忽略。返回被成功移除的元素数量。
sismember key meber
检查元素member是否存在于集合key中。若是是返回1,不是或者key不存在,返回0。
scard key
返回集合包含的元素数量
spop key
随机移除集合中的一个元素,并返回被移除元素。
smembers key
返回集合中包含的全部元素
127.0.0.1:6379> sadd set1 java spring redis (integer) 3 127.0.0.1:6379> smembers set1 1) "redis" 2) "spring" 3) "java" 127.0.0.1:6379> scard set1 (integer) 3 127.0.0.1:6379> srem set1 spring (integer) 1 127.0.0.1:6379> sismember set1 spring (integer) 0 127.0.0.1:6379> smembers set1 1) "redis" 2) "java" 127.0.0.1:6379> sadd set1 mysql spring (integer) 2 127.0.0.1:6379> spop set1 "redis" 127.0.0.1:6379> smembers set1 1) "mysql" 2) "spring" 3) "java" 127.0.0.1:6379>
下面是一些用于处理多个集合的一些命令
sdiff key [key...]
返回存在于第一个集合,但不存在于其余集合中的元素(数学上的差集运算)
sinter key [key...]
返回同时存在于全部集合中的元素(数学上的交集运算)
sunion key [key...]
返回至少存在于一个集合中的元素(数学上的并集运算)
127.0.0.1:6379> smembers set1 1) "mysql" 2) "spring" 3) "java" 127.0.0.1:6379> smembers set2 1) "mysql" 2) "springboot" 3) "redis" 127.0.0.1:6379> sdiff set1 set2 1) "java" 2) "spring" 127.0.0.1:6379> sinter set1 set2 1) "mysql" 127.0.0.1:6379> sunion set1 set2 1) "mysql" 2) "springboot" 3) "java" 4) "spring" 5) "redis" 127.0.0.1:6379>
Redis的hash类型其实就是一个缩减版的redis。它存储的是键值对,将多个键值对存储到一个redis键里面。
hash类型的底层主要也是基于字典这种数据结构来实现的。
redis内部在实现hash数据类型的时候是使用了两种数据结构。在建立一个空的hash表时,默认使用的是ziplist的数据结构,知足必定条件后会转成字典的形式。
hmget hash-key key [key...]
从散列表里面获取一个或多个键的值
hmset hash-key key value [key value...]
为散列表里面的一个或多个键设置值
hdel hash-key key [key...]
删除散列表里面的一个或多个键值对,返回删除成功的键值对的数量
hlen hash-key
返回散列表包含的键值对的数量
hexists hash-key key
检查给定的键是否存在于散列表中
hkeys hash-key
获取散列包含的全部键
hvals hash-key
获取散列包含的全部值
hgetall hash-key
获取散列包含的全部键值对
127.0.0.1:6379> hmset hash1 username tom email 123@123 year 12 OK 127.0.0.1:6379> hmget hash1 email 1) "123@123" 127.0.0.1:6379> hlen hash1 (integer) 3 127.0.0.1:6379> hdel hash1 year (integer) 1 127.0.0.1:6379> hexists hash1 year (integer) 0 127.0.0.1:6379> hkeys hash1 1) "username" 2) "email" 127.0.0.1:6379> hvals hash1 1) "tom" 2) "123@123" 127.0.0.1:6379> hgetall hash1 1) "username" 2) "tom" 3) "email" 4) "123@123" 127.0.0.1:6379>
有序集合相比较于集合,多个有序两个字,咱们知道set集合类型存储的元素是无序的,那Redis有序集合是怎么保证有序的?使用分值,有序集合里存储这成员与分值之间的映射,并提供了分值处理命令,以及根据分值的大小有序地获取成员或分值的命令。
Redis有序集合的实现使用了一种叫跳跃表的数据结构(简称跳表,可自行查阅),同时也使用到了前面提到的压缩列表。也是知足必定条件的话,会自行转换。
zadd z-key score memer [score member...]
将带有给定分值的成员添加到有序集合里面
zrem z-key member [member...]
从有序集合里面移除给定的成员,并返回被移除成员的数量
zcard z-key
返回有序集合包含的成员数量
zincrby z-key increment member
将member成员的分值加上increment
zcount z-key min max
返回分值介于min和max之间的成员数量
zrank z-key member
返回成员member在有序集合中的排名
zscore z-key member
返回成员member的分值
zrange z-key start stop [withscores]
返回有序集合中排名介于start和stop之间的成员,若是给定了可选的withscores选项,name命令会将成员的分值也一并返回。
zrevrank z-key member
返回有序集合里成员member的排名,成员按照分值从大到小排列。
zrevrange z-key start stop
返回有序集合给定排名范围内的成员,成员按照分值从大到小排列。
zrangebyscore z-key min max
返回有序集合中分值介于min和max之间的全部成员
127.0.0.1:6379> zadd zset1 10 a 12 b 1 c 3 d 20 e (integer) 5 127.0.0.1:6379> zcard zset1 (integer) 5 127.0.0.1:6379> zcount zset1 2 10 (integer) 2 127.0.0.1:6379> zrank zset1 d (integer) 1 127.0.0.1:6379> zscore zset1 e "20" 127.0.0.1:6379> zrange zset1 3 5 1) "b" 2) "e" 127.0.0.1:6379> zrevrank zset1 d (integer) 3 127.0.0.1:6379> zrevrange zset1 3 5 1) "d" 2) "c" 127.0.0.1:6379> zrangebyscore zset1 5 10 1) "a" 127.0.0.1:6379>
做者Info: 公众号:二营长的笔记 闲话:用技术筑起本身的风墙,当外面的枪林弹雨来临的时候,至少能够来个“面对疾风吧!!!”