redis应用十分广泛,下面介绍下redis的应用场景。
key的设计原则
简短明了,节省内存;统一形式,eg:功能:业务主键,一看到key就能知道是属于什么模块的。
value的设计原则
尽可能的简短。value值越大,执行速度越慢。对于value过大的考虑是否可以分割。eg:使用key来记录某商城一天的成交记录,如果value值太大,考虑使用key:01~key:24来记录每小时的成交记录。
下面是关于redis中常见数据类型及命令,建议先看下。
1、数据缓存(String)
具体场景:1)、验证码,eg:注册/登陆时的验证码;2)、数据库(修改频率低的)数据缓存到redis,eg:收费配置;3)、会话缓存,eg:登陆的用户信息等。
实现思路:非常简单,在java程序中直接调用set方法,根据需求调用expire方法,取值直接使用get方法。
redis命令:
set key value //插入key,并给key赋值
expire key seconds//设置有效时间
get key //取值
java方法:
String set(final String key, final String value)
expire(final String key, final int seconds)
get(final String key)
2、计数功能(String)
具体场景:1)、文章阅读数或者新闻浏览量;2)、商品库存。
实现思路:将文章id、新闻id,商品id作为key,增加(阅读/浏览)调用incr,商品库存减少则调用decr。
redis命令:
incr key/incrby key increment //key递增(指定值)
decr key/decrby key increment //key递减(指定值)
java方法:
incr(final String key)/incr(final String key)
decr(final String key)/decrBy(final String key, final long integer)
3、分布式锁(String)
具体场景:1)、商品秒杀,eg:双11秒杀、抢火车票等;2)、分布式环境下数值计算(比如商品库存变化)等。
实现思路:使用加锁机制(写一个类,实现Lock接口),每次修改数据前调用lock接口,lock接口实现中是一个尝试获取锁(tryLock)的方法,tryLock的实现使用setnx方法(key为指定值,eg:业务编号等),设置key的有效时间,setnx成功(获取到锁)后才能执行业务操作,执行完业务操作后删除key(释放锁)。
lock:调用tryLock方法,成功则直接返回,不成功则线程sleep一会(eg:10ms)再继续尝试;
tryLock:生成唯一id(记为m,通过uuid或者时间戳+6位自增数),m为setnx的value值,记得保存起来(比如放到ThreadLocal中),之后释放锁会用到;
删除key:通过key拿到redis中的value,与当前线程中的m进行比较,相等,则表示是同一个线程,可以进行del key的操作;不相等则不允许执行del key操作;
setnx特性:不存在则插入并赋值(相当于获取到锁),存在则不作任何处理;
有效时间的作用:线程获取到锁后执行业务出现异常(eg:线程异常中断、业务执行超时等),达到有效时间会释放锁。
redis命令:
/** 推荐使用 */
set key value [expiration EX seconds|PX milliseconds] [NX|XX]
del key
/** 作用等同,但是不推荐使用 */
setnx key value
expire key seconds
del key
java方法:
/** 推荐使用 */
set(final String key, final String value, final String nxxx, final String expx,final long time)//设置成NX
del(final String key)
/** 不推荐使用 */
setnx(final String key, final String value)
expire(final String key, final int seconds)
del(final String key)
4、购物车(hash)
具体场景:1)、获取购物车所有商品信息;2)、添加商品到购物车;3)、商品数量增加或者减少;4)、获取购物车中商品数;5)、删除购物车中商品。
实现思路:使用redis缓存商品id、数量等信息,多个信息可以采用hash数据类型。比如:可以使用用户id作为key,商品id作为field,商品数量作为value。商品相关信息的显示可以通过商品id异步请求后端获取。
redis命令:
hgetall key//获取key的所有信息
hget key field//获取key中field的值
hmset key field value [field value ...]//商品添加到购物车
hincrby key field increment//如果field减少,则increment为负数
hlen key//key中field的数量
hdel key field [field ...]//删除key中的field
java方法:
hgetAll(final String key)
hget(final String key, final String field)
hmset(final String key, final Map<String, String> hash)
hincrBy(final String key, final String field, final long value)
hlen(final String key)
hdel(final String key, final String... field)
5、栈/队列(list)
具体场景:1)、推送信息(eg:新闻)显示;2)、消息队列。
栈:先进后出。实现思路:方式一:使用lpush向list中添加元素,lpop取出元素;方式二:使用rpush向list中添加元素,rpop取出元素。
队列:先进先出。实现思路:方式一:使用lpush向list中添加元素,rpop取出元素;方式二:使用rpush向list中添加元素,lpop取出元素。
阻塞队列:实现思路:方式一:使用lpush向list中添加元素,brpop取出元素;方式二:使用rpush向list中添加元素,blpop取出元素。
lrange key start stop:获取元素,不会删除;lpop/rpop会直接将元素从list中取出。
redis:
lpush key value [value ...]
rpush key value [value ...]
lpop key
rpop key
blpop key [key ...] timeout
brpop key [key ...] timeout
lrange key start stop
java:
lpush(final String key, final String... string)
rpush(final String key, final String... string)
lpop(final String key)
rpop(final String key)
blpop(final int timeout, final String key)
brpop(final int timeout, final String key)
lrange(final String key, final long start, final long end)
6、微信抽奖活动(set)
具体场景:1)、参与抽奖;2)、查看全部参与人;3)、选出中奖者。
实现思路:将点击参与抽奖的用户的微信id加入到set中,可以使用活动id作为key,用户的微信id作为menber,使用set的相关命令获取set中用户的微信id(进而获得用户信息)和随机抽取出中奖者。
redis:
sadd key member [member ...]
smembers key
spop key [count]/srandmember key [count]
java:
sadd(final String key, final String... member)
smembers(final String key)
spop(final String key, final long count)/srandmember(final String key, final int count)
7、交集、并集、差集(set)
具体场景:1)、共同好友、共同爱好(交集);2)、可能认识的人(差集)。
redis:
sinter key [key…]
sdiff key [key…]
java:
sinter(final String... keys)
sdiff(final String... keys)
8、排行榜(zset)
具体场景:1)、搜索热点新闻;2)、游戏排行;3)、音乐播放排名;4)、最新新闻;5)、上面抽奖参与人(点击参与抽奖时间为score)。
实现思路:考虑以搜索热点:日期作为有序集合(zset)的key,以搜索量作为分数值(score),以热点新闻id作为元素。直接使用zset中相关命令进行操作,完成数据的展示。
redis:
zadd key [NX|XX] [CH] [INCR] score member [score member ...]
zincrby key increment member
zrevrange key start stop [WITHSCORES]
//可能用到
zunionstore destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
java:
zadd(final String key, final double score, final String member)
zincrby(final String key, final double score, final String member)
zrevrange(final String key, final long start, final long end)
zunionstore(final String dstkey, final String... sets)
如果有写的不对的地方,请大家多多批评指正,非常感谢!