hello: 大家好
我是1987 今天我给大家带来Java + Redis 应用,这些都是我平时的总结),希望对大家有用。
首先: 我带大家简单的了解一下Redis
Redis常用数据类型(最为常用的数据类型主要有以下五种)
●String
●Hash
●List
●Set
●Sorted set
下面我们先来逐一的分析下这五种数据类型的使用和内部实现方式:
1、String
常用命令:
set,get,decr,incr,mget 等。
常用方法:
set -- 设置key对应的的值为String类型的value
get -- 获取对应key对应的String的值,如果不存在返回nil
setnx -- 设置可以为对应的值为String类型的value,如果key存在返回0不覆盖,不存在返回1
setex -- 置key对应的值为String类型的value,并指定此键值对应的有效期
SETEX key seconds value
例:setex mykey 10 你好
setrange -- 设置key的value的子字符串
setrange -- key 位置 替换的内容如果替换内容没有原value长,则原value剩余的内容将被保留
mset -- 一次设置多个key的值,成功返回ok,失败返回0,要成功都成功,要不成功全部失 败。
例:mset key1 内容一 key2 内容二
msetnx -- 一次设置多个key的值,成功返回ok,失败返回0,不覆盖已经存在的值,要成功都 成功,要失败都失败。
getset -- 设置key的值并返回key的旧值
例:getset key newValuse
getrange -- 获取key对应的value子字符串
例:getrange key 0 5 //获取前6个字符
mget -- 批量获取
例:mget key1 key2 key3 //没有设置则返回空
incr -- 对key的值做增加操作,并返回新的值
incrby -- 对可以的value加指定的值,key如果不存在会设置key并value为0
例:incrby key1 5 //对key1的值加5
decr -- 对key的值做减减操作-1
decrby -- 对key的值减去指定值
append -- 给指定key的字符串追加value,返回新的字符串长度
strlen -- 取指定key的value值的长度
应用场景:
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String,也可以是数字。比如想知道什么时候封锁一个IP地址(访问超过几次)。incrby命令让这些变得很容易,通过原子递增保持计数。常规计数: 微博数, 粉丝数
Hashs
在Memcached中,我们经常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值,比如用户的昵称、年龄、性别、积分等,这时候在需要修改其中某一项时,通常需要将所有值取出反序列化后,修改某一项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。而Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。它是一个String类型的field和value的映射表,它的添加和删除都是平均的,hash特别适合用于存储对象,对于将对象存储成字符串而言,hash会占用更少的内存,并且可以更方便的存取整个对象. 它和java的HashMap完全类似
常用命令:
hget,hset,hgetall 等。
常用方法:
hset -- 设置一个hash 的field为指定值,如果key不存在则先创建
例:hset tab ke1 val1
hget -- 获取某个hash的某个field值
例:hget tab ke1
hsetnx -- 类似string只是操作的是hash
hmset -- 批量设置hash的内容
hmget -- 获取hash表的全部key值
例:Hmget key field1 field2
hincrby -- 给hash表的某个字段增加值
hexists -- 判断hash表中某个key是否存在
hlen -- 返回hash表中的key数量
hdel -- 删除指定hash表的某个键值对
hkeys -- 返回hash表中所有的key
hvals -- 返回hash表中所有的value
hgetall -- 获取hash表中所有key和value
使用场景:
存储部分变更数据。如用户信息等。
Lists
Lists 就是链表,略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api,你可以直接查询,删除Lists中某一段的元素。Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
常用命令:
lpush,rpush,lpop,rpop,lrange等。
常用方法:
lpush -- 在key所对应的list头部添加一个元素 ==》l的意思是left
rpush -- 在key说对应的list尾部添加一个元素 ==》r的意思是right
lrange -- 显示list里面的内容
例:lrange 0 -1 //全部显示
linsert -- 在key对应的list
例:linsert mylist before one myvalue
lset -- 设置list中指定下标元素的值
例:lset mylist index myvalue
lrem -- 从key对应的list中删除n个和value相同的元素,结果返回影响元素的个数,n<0从尾部开 始删除,n=0全删除
例:lrem mylist count "value"
ltrim -- 保留指定key范围内的数据,返回ok成功
例:ltrim mylist 0 3 //0-3是保留的范围
lpop -- 从list的头部删除一个元素,并返回该删除的元素
rpop -- 从list的尾部弹出一个元素,并返回该删除的元素
rpoplpush -- 从第一个list的尾部元素异常元素并添加到第二个list的头部
例:rpoplpush mylistA mylistB
lindex -- 返回list位置的元素
例:lindex mylist 3
llen -- 返回list中元素的个数
例:llen mylist
使用场景
消息队列系统
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。
比如:将Redis用作日志收集器
实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。
Set
常用命令:
sadd,spop,smembers,sunion 等。
实现方式:
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。set中的元素是没有顺序的。
常用方法:
sadd -- 向名称为key的set中添加元素,返回影响元素的个数,0为失败,1为成功
例:sadd myset value
smembers -- 查看集合中所有的成员
例:smebers myset
srem -- 删除集合的一个元素
例:srem myset two
spop -- 随机返回并删除set中一个元素
例:spop myset
sdiff -- 返回所有set与第一个set的差集
例:sdiff myset1 myset2
sdiffstore -- 比较差集并且存储到另一个set中,返回1代表成功
例:sdiffstore setstoreSet mySet1 myset2
sinter -- 返回所有给定集合的交集
例:sinter myset1 mysert2 //1集合和2集合的交集
sinterstore -- 返回给定集合的交集并存储到另一个集合
例:sinterstore desset myset1 myset2 //存到desset集合中
sunion -- 返回所有给定集合的并集
例:sunion set1 set2
sunionstore -- 返回所有的并集并且存储到另一个集合中,返回影响的元素个数
例:sunionstore destSet myset1 myset2
smove --把第一个集合的元素移动到第二个集合中
例:smove myset myset 你好
scard -- 返回集合中元素的个数
例:scard myset1
sismember --测试某个元素是否在集合中,返回0是不是,大于0是存在
例:sismember mykey1 你好
srandmember -- 随机返回个集合中的元素
例:srandmemeber myset1
应用场景:
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
Sorted Sets
常用命令:
zadd,zrange,zrem,zcard等
实现方式:
Redis sorted
set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
常用方法:
zadd -- 向zset中添加元素member,score 用于排序,如果元素存在,则更新其顺序,返回0代 表没添加成功
例:ZADD key score member
zadd myset 3 itim
zrange -- 取出集合中的元素
例:zrange myset 0 -1 withscores//显示序号
zrem -- 删除名称为key的zset中的元素member
例:zrem myset itim
zincrby -- 修改元素的排序,如果元素不存在则添加该元素,且排序的score值为增加值
例:zincrby myzset score itim
zrank -- 返回元素在集合中的排序位置,就是索引值
例:zrank myzset itim //itim在集合中的位置
zrevrank -- 返回从大到小的排序索引值,就是逆序位置
例:zrevrangk myzset itim//逆序的位置
zrevrange -- 返回集合中从大到小排序(降序)的,索引start到end的所有元素
例:zrevrange myzset 0 -1 //逆序后的元素
zrangebyscore -- 根据排序索引的scores来返回元素
例:zrangebyscore myzset 1 3 withscores//
zcount -- 返回集合中给定区间的数量
例:zcount myzset 2 4 //集合中2-4索引元素的个数
zcard -- 返回集合中所有元素的个数
例:zcard myzset //返回所有元素的个数
zremrangebyrank -- 删除集合中排序在给定区间的所有元素(按索引删除)
例:zremrangebyrank myzset 2 3 //
zremrangebyscore -- 删除集合中在给定排序区间的元素 (按顺序删除)
例:zremrangebyscore myzset 2 5 //
使用场景:
Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构。
和Sets相比,Sorted Sets增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如一个存储全班同学成绩的Sorted Sets,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。
总结:
1.根据业务需要选择合适的数据类型,并为不同的应用场景设置相应的紧凑存储参数。
2.当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能以及最大的内存使用量。
3.如果需要使用持久化,根据是否可以容忍重启丢失部分数据在快照方式与语句追加方式之间选择其一,不要使用虚拟内存以及diskstore方式。
4.不要让你的Redis所在机器物理内存使用超过实际内存总量的3/5。