# redis
##### Redis简介:
是以key-value形式存储,和传统的关系型数据库不一样.
不一定遵循传统数据库的一些基本要求.(非关系型的,分布式的,开源的,水平可拓展的)
键可以包含:(string)字符串,哈希,(list)链表,(set)集合,(zset)有序集合.
这些数据集合都指出 push/pop,add/remove及取交集和并集以及更丰富的操作.
redis支持各种不同方式排序,为了 保证效率,数据都是缓存在内存中.
它可以从周期性的把更新的数据写入到磁盘或者把修改操 作写入追加的文件中.
##### 优点:
对数据高并发读写(直接是内存中进行读写的)
对海量数据的高效率存储和访问
对数据的可拓展性和高可用性.
单线程操作,每个操作都是原子操作,没有并发相关问题(redis 6)
##### 缺点:
redis(ACID处理非常简单)
无法做太复杂的关系数据库模型
Redis是以key-value store存储.
redis定位是缓存, 提高数据读写速度, 减轻对数据库存储与访问压力
redis在线入门 : http://try.redis.io/
## redis基本数据类型
##### String类型:
数据类型:Map<String, String> map
set key ->根据键取值
incr key -> 把值递增1
decr key -> 把值递减1
del key -> 根据键删除键值对
setex key timeout value -> 存入键值对,timeout表示失效时间,单位s
ttl ->可以查询出当前的key还剩余多长时间过期
incrby key num -> 偏移值
mset k1 v1 k2 v2 ... -> 批量存入键值对
mget k1 k2 ... -> 批量取出键值
append key ‘value‘ -> 原值后拼接新内容
setnx key value -> 存入键值对,键存在时不存入
setex key timeout value -> 存入键值对,timeout表示失效时间,单位s
ttl ->可以查询出当前的key还剩余多长时间过期
setrange key index value -> 修改键对应的值,index表示开始的索引位置
##### String类型应用场景:
缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysql作为储存层,绝大部分请求数据都是
redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低 后端压力的作用。
key value
user_xxxx : id value...json 格式字符串
计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,
同时数据可以异步落地到其他的数据源。
如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。incr viewnum 1
共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上, 用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,
在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息
都直接从redis中集中获取。
限速/防刷:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率。xxxxx:phone:5 //每分钟发短信5次 decr key
##### hash类型:
数据类型:Map<string, Map<string, ?>>
hset key hashkey hashvalue -> 存入一个hash对象
hget key hashkey -> 根据hash对象键取去值
hexists key hashkey -> 判断hash对象是含有某个键
hdel key hashkey -> 根据hashkey删除hash对象键值对
hincrby key hashkey 递增值 -> 递增hashkey对应的值
hlen key -> 获取hash对象键的数量
hkeys key -> 获取hash对象的所有键
hvals key -> 获取hash对象的所有值
hgetall key -> 获取hash对象的所有数据
##### list类型:
Redis中的List类似Java中的queue,也可以当做List来用.
List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等.更详细的说,List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,list的设计非常简单精巧,即可以作为栈,又可以作为队列.满足绝大多数需求.
**数据类型**:Map<String, List>
rpush key value -> 往列表右边添加数据
lpush key value -> 往列表左边添加数据
lpop key -> 弹出列表最左边的数据
rpop key -> 弹出列表最右边的数据
lrange key start end -> 范围显示列表数据,全显示则设置0 -1
llen key -> 获取列表长度
linsert key before/after refVal newVal -> 参考值之前/后插入数据
lset key index value -> 根据索引修改数据
lrem key count value -> 在列表中按照个数删除数据
ltrim key start end -> 范围截取列表
lindex key index -> 根据索引取列表中数据
**应用场景**:
1.消息队列: redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞时的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性.
2.文章列表:每个用户都有属于自己的文章列表,现在需要分页展示文章列表,
此时可以考虑使用列表,列表不但有序,同时支持按照索引范围获取元素。
xxxx_user_articles:uid [aid1, aid2, aid3.....]
3.朋友圈点赞;
规定:朋友圈内容的格式:
1,内容: user:uid:post:pid content来存储;
user:A:post:1 xxx
user:A:post:2 yyy
user:B:post:1 yyy
2,点赞: post:x:good list来存储;
post:1:good [a, b, c, d]....
1,创建一条朋友圈内容:set user:1:post:91 ‘hello redis‘;
2,点赞:
lpush post:91:good ‘{id:1,name:stef,img:xxx.jpg}‘
lpush post:91:good ‘{id:2,name:lanxw,img:xxx.jpg}‘
lpush post:91:good ‘{id:3,name:fly,img:xxx.jpg}‘
3,查看有多少人点赞: llen post:91:good
4,查看哪些人点赞:lrange post:91:good 0 -1
4.回帖
1,创建一个帖子:set user:1:post:90 ‘wohenshuai‘
2,创建一个回帖:set postreply:1 ‘nonono‘
3,把回帖和帖子关联:lpush post:90:replies 1
4,再来一条回帖:set postreply:2 ‘hehe‘
lpush post:90:replies 2
5,查询帖子的回帖:lrange post:90:replies 0 -1
get postreply:2
##### set类型:
Set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集.
sadd key value -> 往set集合中添加元素
smembers key -> 列出set集合中的元素
srem key value -> 删除set集合中的元素
spop key count -> 随机弹出集合中的元素
sdiff key1 key2 -> 返回key1中特有元素(差集)
sdiffstore var key1 key2 -> 返回key1中特有元素存入另一个set集合
sinter key1 key2 -> 返回两个set集合的交集
sinterstore var key1 key2 -> 返回两个set集合的交集存入另一个set集合
sunion key1 key2 -> 返回两个set集合的并集
sunionstore var key1 key2 -> 返回两个set集合的并集存入另一个set集合
smove key1 key2 value -> 把key1中的某元素移入key2中
scard key -> 返回set集合中元素个数
sismember key value -> 判断集合是否包含某个值
srandmember key count -> 随机获取set集合中元素
**应用场景**:
1,去重;
2,抽奖;
1,准备一个抽奖池:sadd luckydraw 1 2 3 4 5 6 7 8 9 10 11 12 13
2,抽3个三等奖:spop luckydraw 3
3,抽2个二等奖:spop luckydraw 2
4,抽1个二等奖:spop luckydraw 1
3,做set运算(好友推荐)
1,初始化好友圈 sadd user:1:friends ‘user:2‘ ‘user:3‘ ‘user:5‘
sadd user:2:friends ‘user:1‘ ‘user:3‘ ‘user:6‘
sadd user:3:friends ‘user:1‘ ‘user:7‘ ‘user:8‘
2,把user:1的好友的好友集合做并集; sunion user:2:friends user:3:friends
user:1 user:3 user:6 user:7 user:8
3,让这个并集和user:1的好友集合做差集;
合并: sunionstore aa user:2:friends user:3:friends
差集: sdiff aa user:1:friends
user:1 user:6 user:7 user:8
4,从差集中去掉自己
sdiffstore bb aa user:1:friends
srem bb user:1
user:6 user:7 user:8
5,随机选取推荐1个好友
srandmember aa 1
##### zset类型:
zadd key num name -> 存入分数和名称
zincrby key num name -> 偏移名称对应的分数
zrange key start end -> 按照分数升序输出名称
zrevrange key start end -> 按照分数降序输出名称
zrank key name -> 升序返回排名
zrevrank key name -> 降序返回排名
zcard key -> 返回元素个数
zrangebyscore key min max [withscores] -> 按照分数范围升序输出名称
zrevrangebyscore key max min [withscores] -> 按照分数范围降序输出名称
zrem key name -> 删除名称和分数
zremrangebyscore key max min [withscores] -> 根据分数范围删除元素
zremrangebyrank key start end -> 根据排名删除元素
zcount key min max -> 按照分数范围统计个数
应用场景:
排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,
榜单维护可能是多方面:
按照时间、按照播放量、按照获得的赞数等。
##### 总结:
1: 项目操作涉及到缓存操作, 首选 redis
2: 如果确定使用redis, 此时需要考虑使用哪个数据类型
1>如果要排序选用zset
2>如果数据是多个且允许重复选用list
3>如果数据是多个且不允许重复选用set
4>剩下的使用string
java list --- redis list
java set --- redis set
java xxx ----redis JSON.toJsonString(list/set)
###### 设计 key 与 value值
key的设计
1:唯一性
2:可读性
3:灵活性
4:时效性