目录
- Redis五大数据类型
- 通用key操作
- String
-
- 基本操作
- 单数据操作与多数据操作
- 应用场景一
- 应用场景三
- Hash
-
- 基本操作
- 由来
- 数据结构
- 注意事项
- 应用场景
- List
-
- 基本操作
- 注意事项
- 应用场景一
- 应用场景二
- Set
-
- 基本操作
- 数据结构
- 为什么要有set
- 为什么set中的值具有唯一性
- 应用场景一
- 应用场景二
- 应用场景三
- Sorted_Set
-
- 基本操作
- 为什么要有sorted_set
- 注意事项
- 应用场景一
- 应用场景二
Redis五大数据类型
Redis一共支持五种数据类型:String(字符串)、hash(哈希)、list(列表)、set(集合)和zset(sorted set有序集合)
String(字符串):Redis最基本的数据类型,一个键对应一个值,一个键值最大存储512MB
Hash(哈希):hash是一个键值对的集合,是一个String类型的field和value的映射表,适合用于存储对象
List(列表):是redis的简单的字符串列表,按插入顺序排序
Set(集合):是String字符串类型的无序集合,也不可重复
ZSet(sorted set 有序集合)是String类型的有序集合,也不可重复。有序集合中的每个元素都需要指定一个分数,根据分数对元素进行升序排序。
通用key操作
randomKey 随机返回所有key中的某个
Exits key 判断某个key是否存在,返回1或0
del key 删除指定的key
rename key newKey 给指定key改名,如果新的key已经存在,则覆盖原来的key的值
renamenx key newkey 修改key的名称,如果newkey已经存在,则返回0(修改失败),反之1(修改成功)
move key db(这里用0,1,2..) 移动key到其他数据库
ttl key 查询key的有效期(-1:永久有效),返回秒数
expire key 整型值 (秒为单位) 设置key生命周期
persist key 将某个key设置为永久有效
String
key-value形式
基本操作
# 增
set mykey "test" # 设置新值,如果已经存在则覆盖旧值
getset mycounter 0 # 先取值,再设置值(get xxx, set xxx xxx)
setex mykey 10 "hello" # 设置值的过期时间为10s,超过过期时间,值会销毁
mset key1 "abc" key2 "123" # 批量增加
# 删
del mykey # 删除键---值,如果删除成功返回1,否则返回0(没有这个键)
# 改
append mykey "hello" # 在原有值的后面追加,没有就创建,返回追加后的值的长度
incr c1 # 将值+1,没有就创建,并设置初始值为1
decr c1 # 将值-1,没有就创建,并设置初始值为-1
incrby c1 10 # 将值+10,没有就创建,并设置初始值为10
decrby c1 10 # 将值-10,没有就创建,并设置初始值为-10
setrange mykey 20 "dd" # 将第21和22字节替换为"dd",长度不够补0
# 查
exists mykey # 判断该值是否存在,存在返回1,否则返回0
get mykey # 取值
strlen mykey # 获取长度
ttl mykey # 获取存活时间,-1表示永久存活
getrange mykey 1 20 # 获取第2-20个字节,超过了value的长度,则取第1个字节后所有的值
mget key1 key2 # 批量取值
单数据操作与多数据操作

一条以上相同的指令数,多数据操作的执行时间要短
应用场景一
分库分表之后主键怎么保证唯一性
解决方案:
可以用redis中String类型中的incr、decr来实现,这个也不会带来并发造成的数据影响,因为String在redis内部存储默认是一个字符串,当遇到增减类incr、decr时会转成数值型进行计算,redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,所以无需考虑并发带来的数据影响。(数值有上线,java中long型数据最大值[- 2^63, 2^63 - 1])
incr key
incrby key increment
incrbyfloat key increament
decr key
decrby key increment
利用 redis 生成 id : 性能比较好,灵活方便,不依赖于数据库。但是,引入了新的组件造成系统更加复杂,可用性降低,编码更加复杂,增加了系统成本
也有其他解决方案:
UUID:不适合作为主键,因为太长了,并且无序不可读,查询效率低。比较适合用于生成唯一的名字的标示比如文件的名字。
## 应用场景二 一定时间内的有效操作 例子:
- 海选投票,微信投票,每4小时投一票,
- 热门每个商品维持三天,三天之后换下一个商品
- 热点新闻
解决方案:
setex key seconds value
psetex key milliseconds value
redis控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作
应用场景三
粉丝数,博文,关注数
解决方案:
- 在redis中为大V用户设置用户信息,以用户主键和属性值作为key,后台设定定时刷新策略
user:id:35067:fans 12210 user:id:35067:blogs 562 user:id:35067:focus 200
- 在redis中以josn格式存储大V用户信息,定时刷新(也可以用hash类型)
user:id:35067 {id:35067,name:王者 fans:12210,blogs:562,focus:200}
Hash
二维数组:
第一维度:数组
第二维度:链表
基本操作
hmset key field1 value [field2 value ...] # 设置一个或多个字段的值
hset key field value # 设置一个字段的值
hmget key field1 [fiedl2 ...] # 查看一个或多个字段
hget key filed # 查询一个字段
hgetall key # 查看所有字段
hexists key field # 查询是否有这个字段
hkeys key # 获取所有字段
hlen key # 获取字段数量
hvalues # 获取所有的值
hdel key field1 [field2 ...] # 删除一个或多个字段
hincrby key field increment # 为一个字段增加指定值
hincrbyfloat key field increment # 为一个浮点数字段增加指定值
由来
String类型对于对象类数据的存储和管理不方便,需要一个存储空间保存多个键值对数据,并对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
String类型存储对象
hash类型存储对象
数据结构
使用的哈希表结构实现数据存储
注意事项
- hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象,如果数据未获取到,对应的值未(nil)
- 每个hash可以存储2^32-1个键值对
- hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性,但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
- hgetall操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很低,有可能成为数据访问瓶颈
应用场景
电商网站购物车设计与实现
- 以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息
- 将商品编号作为field,购买数量作为value进行存储
- 添加商品:追加全新的field与value
- 浏览:遍历hash
- 更改数量:自增/自减,设置value值
- 删除商品:删除field
- 清空:删除key
List
双向链表的结构
基本操作
BLPOP key1 [key2 ] timeout # 移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
BRPOP key1 [key2 ] timeout # 移出并获取列表最后一个元素,其他同 BLPOP
BRPOPLPUSH source destination timeout # 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
LINDEX key index # 通过索引获取列表中的元素
LINSERT key BEFORE|AFTER pivot value # 在列表的元素前或者后插入元素
LLEN key # 获取列表长度
LPOP key # 移出并获取列表第一个元素
RPOP key # 移出并获取列表的最后一个元素
LPUSH key value1 [value2] # 将一个或多个值插入到列表头部,没有此列表则先创建
RPUSH key value1 [value2] # 将一个或多个值插入到列表尾部,没有此列表则先创建
LPUSHX key value # 将一个值插入到已存在的列表头部
RPUSHX key value # 将一个值插入到已存在的列表尾部
LRANGE key start stop # 获取列表指定范围内的元素
LREM key count value # 移除列表元素
LSET key index value # 通过索引设置列表元素的值
LTRIM key start stop # 删除列表中指定区间外的元素
DEL key # 删除列表
注意事项
- list中保存得数据都是string类型的,数据总容量有限,最多2^32-1个元素
- list具有索引(0,-1)概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
- 获取全部数据操作结束索引设置未-1
- list可以对数据进行分页操作,通常第一页的信息来自list,第二页更多的信息通过数据库的形式加载
应用场景一
微信点赞,应用于具有操作先后顺序的数据控制
key:用户的id
value:点赞的人
点赞:rpush key value
取消点赞:lrem key count value
应用场景二
最新消息的展示,应用于有顺序的消息聚集
企业运营中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出
解决方案:
- 依赖list的数据具有顺序的特征对信息进行管理
- 使用队列模型解决多路信息汇总合并问题
- 使用栈模型解决最新消息的问题
Set
value为nil的hash
基本操作
SADD key member1 [member2] # 向集合添加一个或多个成员,没有此集合则创建
SCARD key # 获取集合的成员数
SINTER key1 [key2] # 返回给定所有集合的交集
SDIFF key1 [key2] # 返回给定所有集合的差集
SUNION key1 [key2] # 返回所有给定集合的并集
SDIFFSTORE destination key1 [key2] # 返回给定所有集合的差集并存储在 destination 中
SINTERSTORE destination key1 [key2] # 返回给定所有集合的交集并存储在 destination 中
SUNIONSTORE destination key1 [key2] # 所有给定集合的并集存储在 destination 集合中
SISMEMBER key member # 判断 member 元素是否是集合 key 的成员
SMEMBERS key # 返回集合中的所有成员
SMOVE source destination member # 将 member 元素从 source 集合移动到 destination 集合
SPOP key # 移除并返回集合中的一个随机元素
SRANDMEMBER key [count] # 返回集合中一个或多个随机数
# 迭代集合中的元素
SSCAN key cursor [MATCH pattern] [COUNT count]
数据结构
底层使用了intset和hashtable两种数据结构存储的,intset我们可以理解为数组,hashtable就是普通的哈希表(key为set的值,value为null)
为什么要有set
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高校的内部存储机制,便于查询
-
set类型:与hash存储结构完成相同,仅存储键,不存储值(nil),并且其中的值是不允许重复的
list有顺序,链表查询数据的效率很低,增删时间复杂度为O(1),查询时间复杂度为O(n)
而hash增删查的时间复杂度都是O(1)
为什么set中的值具有唯一性
因为如果出现相同的value就覆盖了
应用场景一
随机给用户推荐几类数据,应用于随机推荐类信息检索,例如热点歌单推荐,推荐新闻,大V推荐
#随机获取集合中指定数量的数据
srandmember key [count]
#随机获取集合中的某个数据并将该数据移处集合
spop key [count]
应用场景二
共同关注,延申:可以根据共同关注或好友进行推荐好友的物品,应用于同类型不重复数据的合并操作
sdiff key1 key2 #差集
sinter key1 key2 #交集
sunion key1 key2 #并集
#求两个集合的差、交、并集并存储到指定集合中
sdiffstore 新key key1 [key2]
sinterstore 新key key1 [key2]
sunionstore 新key key1 [key2]
#将指定数据从原视集合中移动到目标集合中
smove source destination member
应用场景三
应用于同类型数据的快速去重
统计网站的PV(访问量),UV(独立访客),IP(独立ip)
PV:网站被访问次数,可通过刷新页面提高访问量
UV:网站被不同用户访问的次数,可通过cookie统计访问量,相互用户切换ip地址,uv不变
IP:网站被不同IP地址访问的总次数,可通过IP地址统计访问量,相同的IP不同用户访问,IP不败你
解决方案:
- 利用set集合的数据去重特征,记录各种访问数据
- 建立string类型数据,利用incr统计日访问量(PV)
- 建立set模型,记录不同cookie数量(UV)
- 建立set模型,记录不同IP数量(IP)
Sorted_Set
再set的存储结构基础上添加可排序字段
基本操作
ZADD key score1 member1 [score2 member2] # 向集合添加一个或多个成员,没有此集合则创建
ZCARD key # 获取有序集合的成员数
ZCOUNT key min max # 计算在有序集合中指定区间分数的成员数
ZINCRBY key increment member # 有序集合中对指定成员的分数加上增量 increment
ZINTERSTORE destination numkeys key [key ...] # 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
ZLEXCOUNT key min max # 在有序集合中计算指定字典区间内成员数量
ZRANGE key start stop [WITHSCORES] # 通过索引区间返回有序集合指定区间内的成员
ZRANGEBYLEX key min max [LIMIT offset count] # 通过字典区间返回有序集合的成员
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] # 通过分数返回有序集合指定区间内的成员
ZRANK key member # 返回有序集合中指定成员的索引
ZREM key member [member ...] # 移除有序集合中的一个或多个成员
ZREMRANGEBYLEX key min max # 移除有序集合中给定的字典区间的所有成员
ZREMRANGEBYRANK key start stop # 移除有序集合中给定的排名区间的所有成员
ZREMRANGEBYSCORE key min max # 移除有序集合中给定的分数区间的所有成员
ZREVRANGE key start stop [WITHSCORES] # 返回有序集中指定区间内的成员,通过索引,分数从高到低
ZREVRANGEBYSCORE key max min [WITHSCORES] # 返回有序集中指定分数区间内的成员,分数从高到低排序
ZREVRANK key member # 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
ZSCORE key member # 返回有序集中,成员的分数值
ZUNIONSTORE destination numkeys key [key ...] # 计算给定的一个或多个有序集的并集,并存储在新的 key 中
ZSCAN key cursor [MATCH pattern] [COUNT count] # 迭代有序集合中的元素(包括元素成员和元素分值)
为什么要有sorted_set
- 新需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
- 需要的存储结构:新的存储模型,可以保存可排序的数据
- score不是数据,是用来排序的
注意事项
- score保存的数据存储空间是64位
- score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,使用要谨慎
- sored_set底层存储还是基于set结构,因此数据不能重复,如果重复添加相同的数据,score值将会被反复覆盖,保留最后一次修改的结果(会返回0,代表没有进去,不代表没有覆盖成功)
应用场景一
排名
#正向获取该key中socre中的排名
zrank key member
#倒向获取该key中socre中的排名
zrevrank key member
#获取score值
zscore key member
#增加score值
zincrby key num member
应用场景二
任务权重管理
对于高优先级的任务要保障对其优先处理
解决方案:
- 对于带有权重的任务,优先处理权重高的任务,采用score记录权重即可