zoukankan      html  css  js  c++  java
  • Redis数据结构的多种用法(转载)

    分布式锁(string)

    setnx key value,当key不存在时,将 key 的值设为 value ,返回1。若给定的 key 已经存在,则setnx不做任何动作,返回0。
    当setnx返回1时,表示获取锁,做完操作以后del key,表示释放锁,如果setnx返回0表示获取锁失败。设置过期时期,当遇到宕机时,会在过期后释放锁。

    计数器(string)

    如知乎每个问题的被浏览器次数
    在这里插入图片描述

    set key 0
    incr key // incr readcount::{帖子id} 每阅读一次
    get key // get readcount::{帖子id} 获取阅读量
    

    分布式全局唯一id(string)

    分布式全局唯一id的实现方式有很多,这里只介绍用redis实现
    在这里插入图片描述
    每次获取userId的时候,对userId加1再获取,可以改进为如下形式
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190110202218333.jpg在这里插入图片描述
    直接获取一段userId的最大值,缓存到本地慢慢累加,快到了userId的最大值时,再去获取一段,一个用户服务宕机了,也顶多一小段userId没有用到
    incr :自增1
    incrby:自增一小段

    set userId 0
    incr usrId //返回1
    incrby userId 1000 //返回10001
    

    消息队列(list)

    在list里面一边进,一边出即可

    # 实现方式一
    # 一直往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)就执行如下命令

    lpush msg::li 100
    

    b发了一条微博(编号为200)就执行如下命令:

    lpush msg::li 200
    

     

    假如想拿最近的10条消息就可以执行如下命令(最新的消息一定在list的最左边):

    # 下标从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天生是用来做排行榜的、好友列表, 去重, 历史记录等业务需求
    在这里插入图片描述

    # 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

  • 相关阅读:
    自定义 Spring Boot 安全组件 Security 的用户名和密码的方法
    禁用 Spring Boot 中引入安全组件 spring-boot-starter-security 的方法
    CentOS 7 上配置 maven 的环境变量
    CentOS 7 上配置 JDK1.8 的环境变量
    CentOS 7 上安装 xz utils 解压缩工具
    常用 Maven 配置
    接口统计模板
    为什么领域模型对于架构师如此重要? https://blog.csdn.net/qq_40741855/article/details/84835212
    什么是实体关系图(ERD)? 转
    彻底明白Flink系统学习5:window、Linux本地安装Flink
  • 原文地址:https://www.cnblogs.com/expiator/p/10274151.html
Copyright © 2011-2022 走看看