前言Redis Key
学前准备常用命令 字符串类型
常用命令拓展性操作:如何将一个对象(key)设置成字符串格式(value)应用场景 List类型
图示List链表常用命令知识点应用场景 Set类型
学前须知常用命令简单实践应用场景 Hash类型
学前须知常用命令简单实践应用场景 Zset类型
学前须知常用命令简单实践应用场景 Redis Geo
学前须知常用命令具体应用应用场景 Redis HyperLogLog
学前须知常用命令简单实践应用场景 总结
前言
本文内容参考
1.狂神说,原视频地址链接
2.菜鸟教程
0.下载安装配置redis
1.启动redis
命令行进入到redis的相关配置目录下,该目录结构为:
然后cmd输入命令:
redis-server redis.windows.conf启动redis,启动成功后会看到一个正方体类型的图标表示启动成功,这里就不放截图了.
2.测试是否与redis连接成功
输入ping命令,如果返回一个PONG代表连接成功
常用命令127.0.0.1:6379> ping
PONG
| 命令 | 描述 |
|---|---|
| select [0-15] | 选择当前数据库,redis一共有16个数据库 |
| flushdb | 清空当前数据库中所有的键值 |
| flushall | 清空所有数据库中的所有键值 |
| keys * | 查看所有的键 |
| exists key | 是否存在对应的键,若存在,返回1,不存在则返回0 |
| move key db | 将当前数据库的 key 移动到给定的数据库 db 当中 |
| expire key time | 为key设置一个过期时间,单位为秒,表示time秒后过期 |
| expireat key timestamp | 与expire作用相似,不同的是它接收的是Unix时间戳 |
| ttl key | 查看key的距离过期的剩余时间:若时间为-1,表示没有过期时间,若时间为-2,表示已经过期,若为一个正整数,表示剩余时间 |
| del key | 在 key 存在时删除 key |
| type key | 返回 key 所储存的值的类型 :String、List、Set… |
| 命令 | 描述 |
|---|---|
| set key value | 设置一个值为value,键为key的字符串 |
| get key | 获得键为key的值 |
| append key “s” | 追加字符串s,若key存在则返回一个Integer为新字符串的长度 ,若不存在相当于set key |
| strlen key | 返回 key 所储存的字符串值的长度 |
| incr key | 将 key 中储存的数字值增一 |
| decr key | 将 key 中储存的数字值减一 |
| incrby key step | 将 key 所储存的值加上给定的步长step |
| decrby key step | 将 key 所储存的值减去给定的步长step |
| getrange key start end | 返回 key 中字符串值的子字符,end可以为负数表示从后面开始计算,-1表示最后一个字符 |
| setrange key offset value | 用 value 参数替换给定 key 所储存的字符串值,从偏移量 offset 开始 |
| setex key seconds value | (set with expire:设置过期时间) :相当于设置时就给个过期时间 |
| setnx key value | (set if not exist:不存在时设置,存在这个key时设置失败): 设置成功返回值为1,否则为0 |
| mset k1 v1 [k2 v2…] | 同时设置一个或多个 key-value 对 |
| mget k1 [k2…] | 获取所有(一个或多个)给定 key 的值 |
| msetnx k1 v1[k2 v2…] | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在,这是一个原子性操作,要么都成功,要么都失败 |
| getset key newvalue | 先get这个key的value,(若不存在,则返回nil)返回一个value,然后设置一个新的value替换原来的value |
应用场景我们通常使用Json格式来保存一个对象,Redis中也提供相类似的操作,一共有两种操作方法
①set user:1 {name:hanghang,age:18}
②批量插入方式和批量读取方式
这是一种巧妙地设计:user:{id}:{filed},如此设计在Redis是可以的!
mset user:2:name hanghang user:2:age 20
mget user:2:name user:2:age
我们再来看一下对象的存储结构:
计数器统计多单位的数量对象缓存存储 List类型 图示List链表
常用命令List许多的常用命令大多都是开头以L开始,表示这是一个操作List的命令.
| 命令 | 描述 |
|---|---|
| Lpush key value1 [value2…] | 将一个或多个值插入到列表头部【左】 |
| Rpush key value1 [value2…] | 将一个或多个值插入到列表尾部【右】 |
| Lrange key start end | 获取列表指定范围内的元素,正数代表从头部开始的位置,负数则代表从尾部开始的位置 |
| Lpop | 移除列表的第一个元素,返回值尾移除的元素 |
| Rpop | 移除列表的最后一个元素,返回值为移除的元素 |
| Lindex key index | 通过索引获取列表中的元素,下标从0开始,从列表头部开始 |
| Llen key | 返回列表长度 |
| Lrem key count value | 移除列表中count个的指定元素 |
| Ltrim key start end | 截断[start,stop]外的列表元素,只保留截断内的元素列表 |
| RpopLpush source destination | 移除列表的最后一个元素,并将该元素添加到另一个列表(头)并返回 |
| Exists key | 判断是否存在列表,若存在则返回1,否则返回0 |
| Lset key index value | 通过索引设置列表元素的值(更新指定下标的值),若列表不存在会报错,若指定下标不存在,也会报错 |
| Linsert key before/after item value | 在列表的元素(item)前或者后插入元素(value) |
List相当于一个双向链表,可以从头部或者尾部插入元素,也可以从指定元素的前后插入新的元素如果key不存在,那么创建新的链表,如果key存在,那么插入新的元素.【Rpush、Lpush】如果移除了所有元素,该链表变成空链表表示也不存在!在两边插入或改动值,效率最高,读取中间元素效率会偏低些 应用场景
消息队列消息排队栈使用场景 Set类型 学前须知
学习Java的时候我们也遇到过这个数据结构:Set,里面是存放一些不重复的元素,在Redis的Set是String类型的无序集合,集合成员是唯一的,即这些数据是不重复的。
常用命令与List相类似,Set数据类型的操作命令大多在命令开头处加S以标识
| 命令 | 描述 |
|---|---|
| Sadd key member1 [member2…] | 向Set集合中添加成员 |
| Smembers key | 查看Set中的所有成员值 |
| Sismember key member | 判断某一个成员是否在Set集合中,若存在,则返回1,否则返回0 |
| Scard key | 获取Set集合中的成员个数 |
| Srem key member1 [member2…] | 移除集合中一个或多个成员 |
| Srandmember key [count] | 返回集合中一个或多个随机数 |
| Spop key | 移除并返回集合中的一个随机元素 |
| Smove source destination member | 将 member 元素从 source 集合移动到 destination 集合 |
| Sdiff key1 [key2…] | 返回第一个集合与其他集合之间的差异 |
| Sinter key1 [key2…] | 返回给定所有集合的交集 |
| Sunion key1 [key2…] | 返回所有给定集合的并集 |
| Sinterstore destination key1 [key2…] | 所有给定集合的交集并存储在 destination 中 |
| Sunionstore destination key1 [key2…] | 所有给定集合的并集存储在 destination 集合中 |
该部分只涉及到部分重点、难点的命令.
随机:
127.0.0.1:6379[2]> Sadd myset hello (integer) 1 127.0.0.1:6379[2]> Sadd myset world (integer) 1 127.0.0.1:6379[2]> Sadd myset hanghang (integer) 1 127.0.0.1:6379[2]> Sadd myset hang (integer) 1 127.0.0.1:6379[2]> Srandmember myset #随机返回Set的一个成员变量,但是不删除 "hello" 127.0.0.1:6379[2]> Srandmember myset "world" 127.0.0.1:6379[2]> Smembers myset 1) "world" 2) "hang" 3) "hanghang" 4) "hello" 127.0.0.1:6379[2]> Spop myset #随机弹出Set的一个成员变量,且删除 "hanghang" 127.0.0.1:6379[2]> Spop myset "world" 127.0.0.1:6379[2]> Smembers myset 1) "hang" 2) "hello"
交差并集:
127.0.0.1:6379[2]> Sadd myset1 hang helloworld java #添加成员 (integer) 3 127.0.0.1:6379[2]> Sadd myset2 gui byebye java (integer) 3 127.0.0.1:6379[2]> Sdiff myset1 myset2 #查看差集 1) "hang" 2) "helloworld" 127.0.0.1:6379[2]> Sdiff myset2 myset1 1) "gui" 2) "byebye" 127.0.0.1:6379[2]> Sinter myset1 myset2 #查看交集 1) "java" 127.0.0.1:6379[2]> Sunion myset1 myset2 #查看并集 1) "java" 2) "byebye" 3) "hang" 4) "helloworld" 5) "gui"应用场景
1.共同好友(交集)
2.不重复的信息存储与访问
在数据结构与算法中我们了解到的哈希表就是属于哈希类型的,Java中的Map集合也可以理解为Hash类型(HashMap).它表示一个key–value的键值对类型,在Redis中Hash是一个String类型的key–map(filed,value)的映射表,非常适用于存储对象。
我们来看使用最简单的存储命令得到的对象
127.0.0.1:6379[2]> Hset user1 name hang (integer) 1 127.0.0.1:6379[2]> Hset user1 age 18 (integer) 1
使用Redis Desktop Manager 查看这个对象结构:
与List相类似,Hash命令大多以H开头代表这是一个操作Hash类型的命令。Hash的大多数命令与String类型非常相似,因此可以参照String类型进行学习记忆。
| 命令 | 描述 |
|---|---|
| Hset key field value | 将哈希表 key 中的字段 field 的值设为 value |
| Hget key field | 获取存储在哈希表中指定字段的值 |
| Hmset key field1 value1 [field2 value2 …] | 同时将多个 field-value (键-值)对设置到哈希表 key 中 |
| Hmget key field1 [field2…] | 获取所有给定字段的值 |
| Hgetall key | 获取哈希表key中所有数据:键、值相继出现 |
| Hdel key field1 [field2…] | 删除一个或多个哈希表字段 |
| Hlen key | 获取哈希表中字段的数量 |
| Hexists key field | 哈希表 key 中,指定的字段是否存在,若存在则返回1,否则返回0 |
| Hkeys key | 获取所有哈希表中的字段 |
| Hvals key | 获取哈希表中的所有的值 |
| Hincrby key field increment | 为哈希表 key 中的指定字段的整数值加上增量 increment ,需要注意的是,没有decrby方法,因此可以增加一个负数实现减法 |
| Hincrbyfloat key field increment | 哈希表 key 中的指定字段的浮点数值加上增量 increment |
| Hsetnx key field value | 只有在字段 field 不存在时,设置哈希表字段的值,返回1,否则设置失败,返回0 |
1.使用Hincrby实现字段中的整数值实现自增
127.0.0.1:6379[2]> Hmset employee name guigui age 18 salary 15000 OK 127.0.0.1:6379[2]> Hmset employee2 name guigui age 20 salary 17000.50 OK 127.0.0.1:6379[2]> Hincrby employee salary 150 #测试实现对整数的增加 (integer) 15150 127.0.0.1:6379[2]> Hincrbyfloat employee2 salary -100.50 #测试对浮点数的减少 "16900" 127.0.0.1:6379[2]> Hgetall employee #获得当前key的所有field与value 1) "name" 2) "guigui" 3) "age" 4) "18" 5) "salary" 6) "15150" 127.0.0.1:6379[2]> Hgetall employee2 1) "name" 2) "guigui" 3) "age" 4) "20" 5) "salary" 6) "16900"应用场景
1.对象的存储读取
2.用户信息之类的,经常变动的数据
Zset在Set的基础上,增加了一个值,表示为有序集合,同时,它也是一个String类型的元素集合,不允许出现重复的成员。
常用命令菜鸟教程:
Redis中Zset 通过增加一个double 类型的分数值,来给集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 2 32- 1 。
| 命令 | 描述 |
|---|---|
| Zadd key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
| Zrange key start end | 通过索引区间返回有序集合指定区间内的成员,start |
| Zrevrange key start end | 通过索引区间返回有序集合指定区间内的成员,start>end,否则会报错,表示从大到小返回成员 |
| Zrangebyscore key min max [withscores] | 通过分数返回有序集合指定区间内的成员,withscores表示返回时带上返回集合的分数 |
| Zrevrangebyscore key max min [withscores] | 返回有序集中指定分数区间内的成员,分数从高到低排序 |
| Zrem key member[member …] | 移除有序集合中的一个或多个成员 |
| Zcard key | 获取有序集合中的个数 |
| Zcount key min max | 获取区间的成员数量 |
通过分数排序:
127.0.0.1:6379[2]> Zadd salary 3500 xiaoming (integer) 1 127.0.0.1:6379[2]> Zadd salary 5000 xiaohong 3000 xiaobai (integer) 2 127.0.0.1:6379[2]> Zrange salary 0 -1 1) "xiaobai" 2) "xiaoming" 3) "xiaohong" 127.0.0.1:6379[2]> Zrangebyscore salary -inf +inf #返回所有工资的成员(-∞,+∞) 1) "xiaobai" 2) "xiaoming" 3) "xiaohong" 127.0.0.1:6379[2]> Zrangebyscore salary 3500 5000 #返回工资在3500-5000的成员 1) "xiaoming" 2) "xiaohong" 127.0.0.1:6379[2]> Zrangebyscore salary -inf +inf withscores #返回所有工资的成员,并且返回他们的工资 1) "xiaobai" 2) "3000" 3) "xiaoming" 4) "3500" 5) "xiaohong" 6) "5000" 127.0.0.1:6379[2]> Zrevrangebyscore salary +inf -inf withscores #从高到低返回所有工资的成员,并返回他们的工资 1) "xiaohong" 2) "5000" 3) "xiaoming" 4) "3500" 5) "xiaobai" 6) "3000"应用场景
1.它是排序的Set集合,说明Set可以应用的它也可以应用
2.排行榜、热榜的实现
3.工资排序、成绩排序等各种排序
=-=-=-=-更新线-=-=-=-=
Redis Geo 学前须知到这里已经不再是我们在日常编程中所熟知的类型了,而是在开发中能让我们事半功倍的Redis工具类型的“数据结构”.
常用命令Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作
Geo常用的命令方法有:
| 命令 | 描述 |
|---|---|
| Geoadd | 添加地理位置坐标 |
| Geopos | 获取地理位置的坐标 |
| Geodist | 计算两个位置之间的距离 |
| Georadius | 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合 |
| Georadiusbymember | 根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合 |
| Geohash | 返回一个或多个位置对象的 geohash 值(不常用):位置越接近,哈希字符串越接近 |
由于笔者的Redis版本只有3.0.502,没有达到3.2以上的版本支持,升级太麻烦,因此这里仅仅记录下每个命令的用法,并没有自己去应用实践,以后更新版本了再更新hhh,这里参考菜鸟教程的实例和命令,方便读者理解应用。
- Geoadd命令:
Geoadd key longitude(经度) latitude(维度) member(位置名称) [longitude latitude member …]
注意:
经度范围在[-180度,180度],维度范围不能覆盖到南北极(-85.05112878度到85.05112878度),超出这些范围时,程序会返回一个错误
实例:
redis> Geoadd Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2
- Geopos命令:
Geopos key member [member2 …]
geopos 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil
redis> GEOPOS Sicily Palermo Catania Beijing 1) 1) "13.36138933897018433" 2) "38.11555639549629859" 2) 1) "15.08726745843887329" 2) "37.50266842333162032" 3) (nil) #由于没有添加北京的经纬度信息,即不存在
- Geodist命令:
Geodist key member1 member2 [m|km|ft|mi]
geodist 用于返回两个给定位置(名称)之间的距离,最后一个单位参数表示:米、千米、英里、英尺
redis> GEODIST Sicily Palermo Catania #默认以m为单位返回一个距离 "166274.1516" redis> GEODIST Sicily Palermo Catania km #以千米为单位进行返回 "166.2742" redis> GEODIST Sicily Palermo Catania mi #以英尺为单位进行返回 "103.3182" redis> GEODIST Sicily Foo Bar #若该地点不存在,那么返回空 (nil)
- Georadius命令:
Georadius key longitude(经度) latitude(维度) radius(距离) m|km|ft|mi(单位)
{[withcoord] [withdist] [withhash] [count nums] [ASC|DESC]}
注意:
大括号中的为可选项:
withcoord:带目标地点的经纬度返回
withdist:带目标地点距离此地点的距离返回
withhash:带坐标形成的哈希值返回
count numbers:返回几个地点
ASC|DESC:[ASC:查找结果根据距离从近到远排序;DESC:查找结果根据从远到近排序]
georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素
redis> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
2) "190.4424"
2) 1) "Catania"
2) "56.4413"
redis> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
2) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) 1) "15.08726745843887329"
2) "37.50266842333162032"
redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
2) "190.4424"
3) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) "56.4413"
3) 1) "15.08726745843887329"
2) "37.50266842333162032"
- Georadiusbymember命令
Georadiusbymember key member(存在的成员名称) radius(距离) m|km|ft|mi(单位)
{[withcoord] [withdist] [withhash] [count nums] [ASC|DESC]}
georadiusbymember 和 georedius 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点
redis> GEOADD Sicily 13.583333 37.316667 "Agrigento" (integer) 1 redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km 1) "Agrigento" 2) "Palermo"应用场景
其实读者如果认真实践或者理解了Redis Geo的命令应用,就会了解它对距离的计算和判断是非常强大的,因此它的应用场景也大多和地理位置相关:如:
附近的人地图位置距离显示 Redis HyperLogLog 学前须知
在学习HyperLogLog之前,我们需要认识什么是基数?
基数:基数在数学中其实是一个较为复杂的集合论概念,我们简化将它概括为:如果一个数据集为{1,2,3,4,5,4,3,6},那么它的基数集是{1,2,3,4,5,6},基数是6,可知基数集是集合中不重复元素的集合,基数是这个基数集中元素的个数。
也许通过上面一段引言你会联想到我们数据结构中的一个结构:Set,的确,Set也可以对数据集内的数据实现去重,保证集合内元素的唯一,但是这在某些应用场景下会导致非常大的开销,尤其是确保用户唯一时,如果Set是以Java自带的UUID生成的用户id实现存储,那么每次统计都会造成非常大的开销,因此Redis给我们提供了一个解决方案:HyperLogLog(基数统计算法)
常用命令HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2 64 个不同元素的基数。并且它的错误率仅有0.81%
| 命令 | 描述 |
|---|---|
| PFadd key element[element2…] | 添加指定元素到 HyperLogLog 中 |
| PFcount key [key2…] | 返回给定 HyperLogLog 的基数估算值 |
| PFmerge destkey sourcekey [sourcekey…] | 将多个 HyperLogLog 合并为一个 HyperLogLog |
127.0.0.1:6379[2]> PFadd key:1 a b c d e f g h i j #创建第一组(key:1),并往里面添加相应元素 (integer) 1 127.0.0.1:6379[2]> PFcount key:1 #统计(key:1)组的元素个数 (integer) 10 127.0.0.1:6379[2]> PFadd key:2 i j k m n x y z a b (integer) 1 127.0.0.1:6379[2]> PFcount key:2 (integer) 10 127.0.0.1:6379[2]> PFmerge key:3 key:1 key:2 #合并(key:1)组和(key:2)组的元素,并将其整合到key3组中 OK 127.0.0.1:6379[2]> PFcount key:3 #发现key:3是将key:1和key:2中的重复元素去重了的 (integer) 16 127.0.0.1:6379[2]> PFcount key:1 #key:1组并没有被移除 (integer) 10 127.0.0.1:6379[2]> PFadd key:1 a b z #可以往里面添加重复元素,但不会被重复统计 (integer) 1 127.0.0.1:6379[2]> PFcount key:1 (integer) 11应用场景
用户浏览量等实时发生改变且规定每个用户仅能贡献1次浏览量的应用允许容错,若不允许容错,那么使用Set会更佳 总结
本篇博客仅仅对Redis中常用的五种数据类型和开发中可能会用到的Geo和HyperLogLog的命令作总结和汇总,这些命令也足够我们进行绝大多数的开发使用了,这并不是万能的,遇到困难和问题或者部分缺少的命令还是去官方文档上查找肯定是最好的解决方案~



