分布式锁(string)
setnx key value,当key不存在时,将 key 的值设为 value ,返回1。若给定的 key 已经存在,则setnx不作任何动做,返回0。
当setnx返回1时,表示获取锁,作完操做之后del key,表示释放锁,若是setnx返回0表示获取锁失败。设置过时时期,当遇到宕机时,会在过时后释放锁。html
计数器(string)
如知乎每一个问题的被浏览器次数
java
set key 0 incr key // incr readcount::{帖子id} 每阅读一次 get key // get readcount::{帖子id} 获取阅读量
分布式全局惟一id(string)
分布式全局惟一id的实现方式有不少,这里只介绍用redis实现
每次获取userId的时候,对userId加1再获取,能够改进为以下形式

在list里面一边进,一边出便可sql
# 实现方式一 # 一直往list左边放 lpush key value # key这个list有元素时,直接弹出,没有元素被阻塞,直到等待超时或发现可弹出元素为止,上面例子超时时间为10s brpop key value 10 # 实现方式二 # 一直往list右边放 rpush key value blpop key value 10
新浪/Twitter用户消息列表(list)
假如说小编li关注了2个微博a和b,a发了一条微博(编号为100)就执行以下命令shell
lpush msg::li 100
b发了一条微博(编号为200)就执行以下命令:数据库
lpush msg::li 200
假如想拿最近的10条消息就能够执行以下命令(最新的消息必定在list的最左边):api
# 下标从0开始,[start,stop]是闭区间,都包含 lrange msg::li 0 9
抽奖活动(set)
# 参加抽奖活动 sadd key {userId} # 获取全部抽奖用户,大轮盘转起来 smembers key # 抽取count名中奖者,并从抽奖活动中移除 spop key count # 抽取count名中奖者,不从抽奖活动中移除 srandmember key count
实现点赞,签到,like等功能(set)
# 1001用户给8001帖子点赞 sadd like::8001 1001 # 取消点赞 srem like::8001 1001 # 检查用户是否点过赞 sismember like::8001 1001 # 获取点赞的用户列表 smembers like::8001 # 获取点赞用户数 scard like::8001
实现关注模型,可能认识的人(set)
seven关注的人
sevenSub -> {qing, mic, james}
青山关注的人
qingSub->{seven,jack,mic,james}
Mic关注的人
MicSub->{seven,james,qing,jack,tom}浏览器
# 返回sevenSub和qingSub的交集,即seven和青山的共同关注 sinter sevenSub qingSub -> {mic,james} # 我关注的人也关注他,下面例子中我是seven # qing在micSub中返回1,不然返回0 sismember micSub qing sismember jamesSub qing # 我可能认识的人,下面例子中我是seven # 求qingSub和sevenSub的差集,并存在sevenMayKnow集合中 sdiffstore sevenMayKnow qingSub sevenSub -> {seven,jack}
电商商品筛选(set)
每一个商品入库的时候即会创建他的静态标签列表如,品牌,尺寸,处理器,内存缓存
# 将拯救者y700P-001和ThinkPad-T480这两个元素放到集合brand::lenovo sadd brand::lenovo 拯救者y700P-001 ThinkPad-T480 sadd screenSize::15.6 拯救者y700P-001 机械革命Z2AIR sadd processor::i7 拯救者y700P-001 机械革命X8TIPlus # 获取品牌为联想,屏幕尺寸为15.6,而且处理器为i7的电脑品牌(sinter为获取集合的交集) sinter brand::lenovo screenSize::15.6 processor::i7 -> 拯救者y700P-001
排行版(zset)
redis的zset天生是用来作排行榜的、好友列表, 去重, 历史记录等业务需求
ruby
# user1的用户分数为 10 zadd ranking 10 user1 zadd ranking 20 user2 # 取分数最高的3个用户 zrevrange ranking 0 2 withscores
发布,订阅消息(消息通知)
好比你关注了迪丽热巴,迪丽热巴发微博你就会收到推送
引用: https://www.cnblogs.com/xinde123/p/8489054.html
redis的发布与订阅(发布/订阅)是它的一种消息通讯模式,一方发送信息,一方接收信息。
下图是三个客户端同时订阅同一个频道
下图是有新信息发送给频道1时,就会将消息发送给订阅它的三个客户端
java实现 redis的发布订阅
回顾java如何操做redis:
redis是一种缓存数据库,它也是C/S的结构,也就是客户端和服务端,通常来讲,在java中,咱们一般使用 jedis(客户端)去操做redis(服务端),这其中操做的时候,二者之间确定要创建链接,就像数据库连接同样,在关系型数据库中,咱们通常都维护一个链接池,以达到连接的复用,来省去创建链接和关闭链接的时间。因此在jedis中,一样也存在一个jedispool(jedis链接池)的概念,咱们都是从池中去取链接使用。
引入jedis依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.0</version> </dependency>
创建一个Publisher (发布者)
package pubsub; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * Created by Yuk on 2019/1/10. */ public class Publisher extends Thread{ private final JedisPool jedisPool; public Publisher(JedisPool jedisPool) { this.jedisPool = jedisPool; } @Override public void run() { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); Jedis jedis = jedisPool.getResource(); //链接池中取出一个链接 while (true) { String line = null; try { line = reader.readLine(); if (!"quit".equals(line)) { jedis.publish("mychannel", line); //从 mychannel 的频道上推送消息 } else { break; } } catch (IOException e) { e.printStackTrace(); } } } }
再创建一个订阅者
package pubsub; import redis.clients.jedis.JedisPubSub; /** * Created by Yuk on 2019/1/10. */ public class Subscriber extends JedisPubSub { public Subscriber(){} @Override public void onMessage(String channel, String message) { //收到消息会调用 System.out.println(String.format("receive redis published message, channel %s, message %s", channel, message)); } @Override public void onSubscribe(String channel, int subscribedChannels) { //订阅了频道会调用 System.out.println(String.format("subscribe redis channel success, channel %s, subscribedChannels %d", channel, subscribedChannels)); } @Override public void onUnsubscribe(String channel, int subscribedChannels) { //取消订阅 会调用 System.out.println(String.format("unsubscribe redis channel, channel %s, subscribedChannels %d", channel, subscribedChannels)); } }
这里订阅者须要继承JedisPubSub,来重写它的三个方法。用途 注释上已经写了,很简单。
咱们这里只是定义了一个订阅者,下面去订阅频道。
package pubsub; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * Created by Yuk on 2019/1/10. */ public class SubThread extends Thread { private final JedisPool jedisPool; private final Subscriber subscriber = new Subscriber(); private final String channel = "mychannel"; public SubThread(JedisPool jedisPool) { super("SubThread"); this.jedisPool = jedisPool; } @Override public void run() { System.out.println(String.format("subscribe redis, channel %s, thread will be blocked", channel)); Jedis jedis = null; try { jedis = jedisPool.getResource(); //取出一个链接 jedis.subscribe(subscriber, channel); //经过subscribe 的api去订阅,入参是订阅者和频道名 } catch (Exception e) { System.out.println(String.format("subsrcibe channel error, %s", e)); } finally { if (jedis != null) { jedis.close(); } } } }
最后,再写一个测试类去跑一下。键盘输入消息,订阅者就会触发onMessage方法
package pubsub; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * Created by Yuk on 2019/1/10. */ public class PubSubDemo { public static void main( String[] args ) { // 链接redis服务端 JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379); System.out.println(String.format("redis pool is starting, redis ip %s, redis port %d", "127.0.0.1", 6379)); SubThread subThread = new SubThread(jedisPool); //订阅者 subThread.start(); Publisher publisher = new Publisher(jedisPool); //发布者 publisher.start(); } }
原文地址: https://blog.csdn.net/yu_kang/article/details/86254297