Redis五大数据类型
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。
本文章简单介绍各种类型的基础用法 本文章参考了狂神的视频此处
Redis-Key
代码语言:javascript复制exists key 判断是否存在key
move key 移除key
expire key 10 设置10秒后key过期
ttl key 查看key剩余过期时间
type key 查看key的类型
代码语言:javascript复制 命令 描述
Redis Type 命令 返回 key 所储存的值的类型。
Redis PEXPIREAT 命令 设置 key 的过期时间亿以毫秒计。
Redis PEXPIREAT 命令 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
Redis Rename 命令 修改 key 的名称
Redis PERSIST 命令 移除 key 的过期时间,key 将持久保持。
Redis Move 命令 将当前数据库的 key 移动到给定的数据库 db 当中。
Redis RANDOMKEY 命令 从当前数据库中随机返回一个 key 。
Redis Dump 命令 序列化给定 key ,并返回被序列化的值。
Redis TTL 命令 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
Redis Expire 命令 seconds 为给定 key 设置过期时间。
Redis DEL 命令 该命令用于在 key 存在是删除 key。
Redis Pttl 命令 以毫秒为单位返回 key 的剩余的过期时间。
Redis Renamenx 命令 仅当 newkey 不存在时,将 key 改名为 newkey 。
Redis EXISTS 命令 检查给定 key 是否存在。
Redis Expireat 命令 EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
Redis Keys 命令 查找所有符合给定模式( pattern)的 key 。
String(字符串)
代码语言:javascript复制set k1 v1 设置一个 key为 k1 值为 v1
get k1
APPEND k1 "hello" 向k1中追加一个字符串hello 如果当前key不存在就相当于set key
get k1 取出来"v1hello"
STRLEN k1 获取字符串长度
incr key key值 自增1
decr key key值-- 自减1
incrby key 10 key值 10
decrby key 5 key值-5
字符串范围
getrange key 0 2 获取key的value中 前三个字符[0,2]
getrange key 0 -1 获取key中所有的字符 和get key是一样的
替换
setrange key 2 h 把key值的第三个字符开始的字符串替换成 h
setex(set with expire) 设置过期时间
setex key 30 "hello" 写一个key 值为 hello 字符串过期时间为30秒
setnx (set with not expire) 如果当前值不存在我们创建
setnx key "hh"
设置成功返回1 设置不成功返回0 在分布式锁中经常使用
批量设置值
mset 批量设置多个值 空格分割
mset k1 v1 k2 v2 k3 v3
mget 获取多个值
mget k1 k2 k3
msetnx 如果不存在我们创建 如果 设置多对值其中一对值存在则添加失败(原子性操作)
mestnx k1 v1 k4 v4 k1存在创建失败
#存储对象
set user:1 {name:zhangsan,age:23} 设置一个user:1对象 值为json字符串来保存一个对象!
这里的key是一个巧妙地设计
user:{id}:{filed}
mset user:1:name zhangsan user:1:age 22
mget user:1:name user:1:age
组合命令 getset 先get然后再set
getset db redis 如果不存在值则 返回null
如果存在值,则获取原来的值,并设置新的值(覆盖原来的)
String类似的使用场景value除了是我们的字符串还可以是我们的数字
代码语言:javascript复制 计数器
统计数量
List
基本的数据类型,列表
在Redis中我们可以把list当做栈,队列,阻塞队列!
所有的list命令都是l开头的
代码语言:javascript复制放入值 push
lpush list one 将一个或多个值,插入到列表的头部(左)
rpush list two 将一个值或多个值,插入到列表的尾部(右)
lrange list 0 1 获取list中的值 通过区间获取具体的值
取出 pop
lpop 移除列表的第一个元素
rpop 移除列表的最后一个元素
获取下标
lindex list 1 通过下表获取list中得某一个值
长度
llen list 返回列表的长度
移除指定的值 lrem
取关 uid
lrem list 1 one 移除list中指定个数的value,精确匹配
修剪 trim
ltrim list 1 2 通过下标截取指定的长度 这个list已经被改变了 只剩下截取的元素
rpoplpush 移除列表的最后一个元素将它移动到新的列表中
rpoplpush mylist myotherlist
lrange mylist 0 -1 查看原来的列表
lrange myotherlist 0 -1查看目标列表中,确实存在该值
**lset 将列表中指定下标的值替换为另外一个值**
exists list 判断这个列表是否存在
lset list 0 item 如果不存在列表我们去更新就会报错 如果存在就会更新当前下标的值
linsert 将某个具体的value插入到列表中某个元素的前面或者后面 前面before 后面after
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> linsert list after value1 other
(integer) -1
127.0.0.1:6379> linsert list after item other
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "item"
2) "other"
总结 :
实际上是一个链表
before node after ,left和right都可以插入值
如果key不存在,创建新的链表
如果key存在新增内容
如果移除了key所有的value都消失了 空链表也代表不存在
Set(集合 值不能重复)
代码语言:javascript复制sadd myset hello set集合中添加元素
smembers myset 查看指定set集合的所有值
127.0.0.1:6379> sismember myset feifei 判断某一个值是不是在set中
如果set集合中存在 feifei返回1
(integer) 1
127.0.0.1:6379> sismember myset hah 如果set集合中不存在hah返回0
(integer) 0
127.0.0.1:6379> scard myset 获取set集合中的元素个数
(integer) 2
127.0.0.1:6379> sadd myset feifei set集合不能添加相同的元素
(integer) 0
127.0.0.1:6379> sadd myset love
(integer) 1
127.0.0.1:6379> scard myset
(integer) 3
移除元素
代码语言:javascript复制127.0.0.1:6379> srem myset love 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> smembers myset
1) "feifei"
2) "hello
set无序不重复集合 抽取随机元素
代码语言:javascript复制127.0.0.1:6379> srandmember myset 随机抽取一个元素
1) "hello"
127.0.0.1:6379> srandmember myset 1 随机抽取指定个数的元素
1) "hello"
127.0.0.1:6379> srandmember myset 1
1) "feifei"
删除指定的key随即删除key!
代码语言:javascript复制127.0.0.1:6379> smembers myset
1) "feifei"
2) "hello"
127.0.0.1:6379> spop myset 随机删除set集合中得元素
"hello"
127.0.0.1:6379> spop myset
"feifei"
127.0.0.1:6379> smembers myset
(empty list or set)
将一个指定的值,移动到另外一个set集合中
代码语言:javascript复制127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset feifei 添加元素
(integer) 1
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset love
(integer) 1
127.0.0.1:6379> sadd myset2 feifei2 在myset2集合中添加一个 feifei2 元素
(integer) 1
127.0.0.1:6379> smove myset myset2 feifei 移动 myset中的元素 feifei 到myset2中
(integer) 1
127.0.0.1:6379> smembers myset2
1) "feifei"
2) "feifei2"
微博 共同好友(交集)
数字集合类 :
-差集 sdiff key1 key2 第一个集合中的元素减去第二个集合中的元素剩余的一集合中的元素
就是第一个集合中有,第二个集合中没有的元素
代码语言:javascript复制127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key1 d
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2
1) "b"
2) "a"
-交集
集合1 和 集合2 相同的元素
代码语言:javascript复制sinter key1 key2
1) "c"
2) "d"
-并集
并集 集合1和集合2所有的元素加在一起
代码语言:javascript复制127.0.0.1:6379> sunion key1 key2
1) "a"
2) "d"
3) "b"
4) "c"
5) "e"
例:wei博中,A用户将所有关注的人放在一个set集合中,将它的粉丝也放在一个集合中!
共同关注 , 取并集就可以了
共同关注,共同爱好等等
Hash(哈希 )
例如map集合 本质和String类型没有太大区别,还是一个简单的key-value!
key- 集合 这时候值是一个map集合
set myhash field feifei
代码语言:javascript复制127.0.0.1:6379> hset myhash field1 feifei 向myhash中放入一个 field1 feifei 键值对
(integer) 1
127.0.0.1:6379> hget myhash field1
"feifei" 取出键field1中的值
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK 批量放入多个键值对
127.0.0.1:6379> hmget myhash field1 field2
1) "hello" 批量取出多个键对应的值
2) "world"
127.0.0.1:6379> hgetall myhash
1) "field1" 取出myhash中所有键值对
2) "hello"
3) "field2"
4) "world"
删除
127.0.0.1:6379> hdel myhash field2 删除hash指定的key字段!对应的value值也就消失了
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
查看长度
代码语言:javascript复制127.0.0.1:6379> hlen myhash 查看myhash的长度
(integer) 1
判断hash中的指定字段是否存在
代码语言:javascript复制127.0.0.1:6379> hexists myhash field1
(integer) 1
127.0.0.1:6379> hexists myhash field2
(integer) 0
只获得所有的field
代码语言:javascript复制127.0.0.1:6379> hkeys myhash
1) "field1"
获得所有的value
代码语言:javascript复制127.0.0.1:6379> hvals myhash
1) "hello"
127.0.0.1:6379> hset myhash field2 2 向myhash表中设置 key value
(integer) 1
127.0.0.1:6379> hincrby myhash field2 2 自增2
(integer) 4
127.0.0.1:6379> hincrby myhash field2 -1 自增-1相当于-1
(integer) 3
127.0.0.1:6379> hsetnx myhash field2 hello 如果不存在可以设置值 如果存在不能设置 这里我们field2存在了所以设置失败
(integer) 0
用户信息的保存 hash更适合对象的存储 String更加适合字符串的存储
代码语言:javascript复制127.0.0.1:6379> hset user:1 name feifei
(integer) 1
127.0.0.1:6379> hget user:1 name
"feifei"
Zset(有序集合)
在set的基础上增加了一个值 set k1 v1 zset k1 score1 v1 可以排序
添加
代码语言:javascript复制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"
排序实现
代码语言:javascript复制127.0.0.1:6379> zrange salary 0 -1 withscores 从小到大排序 并且附带成绩
1) "xiaozhang"
2) "2500"
3) "zhangsan"
4) "3000"
5) "feifei"
6) "10000"
代码语言:javascript复制zrange salary 0 -1 显示全部用户从小到大
代码语言:javascript复制127.0.0.1:6379> zrevrange salary 0 -1 从大到小排序
1) "feifei"
2) "xiaozhang"
127.0.0.1:6379> zrange salary 0 -1 withscores 获得成员按分数值递增 从小到大 排列的排名。
1) "xiaozhang"
2) "2500"
3) "feifei"
4) "10000"
获取元素个数
代码语言:javascript复制127.0.0.1:6379> zcard salary
(integer) 2
获取指定区间的成员数量
代码语言:javascript复制127.0.0.1:6379> zcount salary 500 3000
(integer) 1
使用场景:排序 存储班级成绩表 工资表排序!
普通消息1 重要消息2 带权重判断
排行榜实现
三种特殊关系数据类型
geospatial(地理位置)
定位 附近的人 两地点之间的距离
redis的Geo可以查询一些测试数据 3.2版本推出 这个功能可以推算地理位置的信息 两地之间的距离 附近的人
代码语言:javascript复制 命令 描述
Redis GEOHASH 命令 返回一个或多个位置元素的 Geohash 表示
Redis GEOPOS 命令 从key里返回所有给定位置元素的位置(经度和纬度)
Redis GEODIST 命令 返回两个给定位置之间的距离
Redis GEORADIUS 命令 以给定的经纬度为中心, 找出某一半径内的元素
Redis GEOADD 命令 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中
Redis GEORADIUSBYMEMBER 命令 找出位于指定范围内的元素,中心点是由给定的位置元素决定
geoadd 添加地理位置 (经度 纬度 名称 )添加到指定的key中
规则 : 两级无法直接添加我们一般会下载城市数据 直接通过java一次性导入
代码语言:javascript复制127.0.0.1:6379> geoadd china:city 120.153576 30.287459 hangzhou 添加地理位置
(integer) 1
127.0.0.1:6379> geoadd china:city 126.642464 45.756967 harbin
(integer) 1
127.0.0.1:6379> geoadd china:city 116.405285 39.904989 beijing
(integer) 1
geopos
获得地点的定位 一个坐标值
代码语言:javascript复制127.0.0.1:6379> geopos china:city beijing 获取指定城市的经度和纬度
1) 1) "116.40528291463852"
2) "39.904988422912503"
geodist返回两个地点之间的距离
如果两个位置之间的其中一个不存在, 那么命令返回空值。
指定单位的参数 unit 必须是以下单位的其中一个:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。
GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
代码语言:javascript复制127.0.0.1:6379> geodist china:city beijing hangzhou 查看北京到杭州的直线距离
"1122483.2754"
127.0.0.1:6379> geodist china:city beijing hangzhou m 查看北京到杭州的直线距离 单位为米
"1122483.2754"
127.0.0.1:6379> geodist china:city beijing hangzhou km 查看北京到杭州的直线距离 单位为km
"1122.4833"
附近的人
1.获得所有附近的人的地址 通过半径来查询
georedius 以给定的经纬度为中心 找出某一半径内的元素 所有的数据应该录入到China:city中
代码语言:javascript复制127.0.0.1:6379> georadius china:city 110 30 1000 km 查找 经纬度 110 30 半径1000km内的城市
1) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist 查找 经纬度 110 30 withdist显示到中心距离的位置
georadius china:city 120 40 1000 km withdist withcoord 显示他人的定位信息
1) 1) "beijing"
2) "306.6596"
3) 1) "116.40528291463852"
2) "39.904988422912503"
2) 1) "harbin"
2) "837.9133"
3) 1) "126.64246469736099"
2) "45.756967600949636"
查询一个城市一定范围内所有的城市
代码语言:javascript复制127.0.0.1:6379> georadiusbymember china:city hangzhou 1000 km 以杭州为中心1000km内的城市
1) "hangzhou"
geohash 返回一个或多个位置元素的geohash表示
该命令将返回11个字符的Geohash字符串!
代码语言:javascript复制127.0.0.1:6379> geohash china:city beijing harbin 将二维的经纬度转换为一维的字符串
1) "wx4g0b7xrt0"
2) "yb4h3cf1xk0"
geo的实现原理其实就是zset有序集合 我们可以使用zset操作geo
代码语言:javascript复制127.0.0.1:6379> zrem china:city shanghai 移除城市中的上海
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1 查看地图中所有的元素
1) "hangzhou"
2) "shanghai"
hyperloglog(基数)
什么是基数? 一个集合内不重复的数就是基数
a{1,3,5,7,8,7}
b{1,3,5,7,8}
基数(不重复的元素)=5
Rdies Hyperloglog 基数统计的算法
优点占得内存是固定的
网页的uv(一个人访问一个网站多次但还是算作一个人!)
传统的方式 set保存用户的id, 然后就可以统计set中的元素数量作为标准判断!
这个方式保存大量的用户id 比较麻烦! 我们的目的是为了计数而不是为了保存用户id;
使用:
代码语言:javascript复制127.0.0.1:6379> pfadd mykey a b c d e f 添加第一组元素
(integer) 1
127.0.0.1:6379> pfcount mykey 统计mykey中基数数量
(integer) 6
127.0.0.1:6379> pfadd mykey1 a b c d e e f 添加第二组元素
(integer) 1
127.0.0.1:6379> pfcount mykey1
(integer) 6
127.0.0.1:6379> pfmerge mykey2 mykey mykey1 合并两组元素(并集)
OK
127.0.0.1:6379> pfcount mykey2 查看并集的数量
(integer) 6
如果允许容错 那么一定可以使用hyperloglog!
如果不允许容错,就使用set或者自己的数据类型即可
bitmaps(位图)
位存储
统计用户信息 分为活跃和不活跃
登录 未登录!
bitmaps位图数据结构 操作二进制数来记录只有0和1 两个状态
记录周一到周日的打卡
打卡 : 1 没打卡 :0
代码语言:javascript复制127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(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 0
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
查看某一天是否有打卡
代码语言:javascript复制127.0.0.1:6379> getbit sign 1 查看第二天
(integer) 1
127.0.0.1:6379> getbit sign 2 查看第三天
(integer) 0
统计打卡天数!
代码语言:javascript复制127.0.0.1:6379> bitcount sign
(integer) 5