Redis的5种数据类型-2

list

数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储数据:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现

 在这里插入图片描述

业务场景-最新消息的展示

  • twitter、新浪微博、腾讯微博中个人用于的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面

在这里插入图片描述

list类型数据操作注意事项

    list 中保存的数据都是string类型的,数据总容量式是有限的,最多232-1个元素(4294967295)
    list具有索引的概念,但是操作数据时候通常以队列的形式进行入队出队操作,或以栈的形式进入栈出栈的操作
    获取全部数据操作结束索引设置为-1
    list 可以对数据进行分页操作,通过第一页的信息来自list,第2页及更多的信息通过数据库的形式加载

List类型应用实践

Redis的list类型相当于java中的LinkedList,其原理就就是一个双向链表。支持正向、反向查找和遍历等操作,插入删除速度比较快。经常用于实现热销榜,最新评论等的设计。

lpush(压栈:先进后出)

在key对应list的头部添加字符串元素

redis 127.0.0.1:6379> lpush mylist "world"
(integer) 1
redis 127.0.0.1:6379> lpush mylist "hello"
(integer) 2
redis 127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379>

 其中,Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推

rpush(先进先出)

在key对应list的尾部添加字符串元素

redis 127.0.0.1:6379> rpush mylist2 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist2 "world"
(integer) 2
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379>

 del(删除集合)

redis 127.0.0.1:6379> del mylist

linsert

在key对应list的特定位置之前或之后添加字符串元素

redis 127.0.0.1:6379> rpush mylist3 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist3 "world"
(integer) 2
redis 127.0.0.1:6379> linsert mylist3 before "world" "there"
(integer) 3
redis 127.0.0.1:6379> lrange mylist3 0 -1
1) "hello"
2) "there"
3) "world"
redis 127.0.0.1:6379>

lrem(-n代表删除n个)

从key对应list中删除count个和value相同的元素,count>0时,按从头到尾的顺序删除,count<0时,按从尾到头的顺序删除,count=0时,删除全部

ltrim

保留指定key 的值范围内的数据(只保留范围内的,其余全部删除,从左到右)

lpop

从list的头部删除元素,并返回删除元素

redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379> rpop mylist2
"world"
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
redis 127.0.0.1:6379>

llen

返回key对应list的长度:

redis 127.0.0.1:6379> lrange mylist5 0 -1
1) "three"
2) "foo"
redis 127.0.0.1:6379> lindex mylist5 0
"three"
redis 127.0.0.1:6379> lindex mylist5 1
"foo"
redis 127.0.0.1:6379>

rpoplpush

从第一个list的尾部移除元素并添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个list是空或者不存在返回nil:
rpoplpush lst1 lst1
rpoplpush lst1 lst2

小节面试分析

    如何基于redis实现一个队列结构?(lpush/rpop)
    如何基于redis实现一个栈结构?(lpush/lpop)
    如何基于redis实现一个阻塞式队列?(lpush/brpop)
    如何实现秒杀活动的公平性?(先进先出-FIFO)
    通过list结构实现一个消息队列(顺序)吗?(可以,FIFO->lpush,rpop)
    用户注册时的邮件发送功能如何提高其效率?(邮件发送是要调用三方服务,底层通过队列优化其效率,队列一般是list结构)
    如何动态更新商品的销量列表?(卖的好的排名靠前一些,linsert)
    商家的粉丝列表使用什么结构实现呢?(list结构)

list使用场景

业务描述

在设计一个秒杀或抢购系统时,为了提高系统的响应速度,通常会将用户的秒杀或抢购请求先存储到一个redis队列,这里我们就基于redis实现一个先进先出队列,例如:

在这里插入图片描述

 代码实现

package com.jt.redis;

import redis.clients.jedis.Jedis;

import java.util.List;

/**
 * 演示抢购活动中的秒杀队列
 * 数据逻辑结构:list
 * 算法:FIFO (公平特性)
 * 数据存储结构:redis中的list类型进行存储
 *
 * 在抢购活动中会执行这样的操作:
 * 1)生产者(购买商品的用户):创建请求并将请求存储到队列
 * 2)消费者(处理购买请求的底层对象):从队列取请求,然后处理请求
 */
public class SecondsKillDemo01 {
     /**
     * 入队操作
     */
     public static void enque(String request){
         Jedis jedis=new Jedis("192.168.126.129", 6379);
         jedis.lpush("queue-1",request);
         jedis.close();
     }
    /**
     * 出队操作
     */
     public static String deque(){
         Jedis jedis=new Jedis("192.168.126.129", 6379);
         //非阻塞式取数据
         //return jedis.rpop("queue-1");
         //阻塞式取数据
         List<String> list = jedis.brpop(60, "queue-1");
         jedis.close();
         return list!=null?list.get(1):null;//0为key
     }

    public static void main(String[] args) {
        //1.构建生产对象(购买商品的用户)
        Thread t1=new Thread(){
            @Override
            public void run() {
                int i=1;
                for(;;){
                    enque("request-"+i++);
                    try { Thread.sleep(1000);
                    }catch (Exception e){}
                }
            }
        };
        //2.构建消费者对象(处理请求的对象)
        Thread t2=new Thread(){
            @Override
            public void run() {
                for(;;){
                    String request=deque();
                    if(request==null)continue;
                    System.out.println("process "+request);
                }
            }
        };
        //3.开启抢购活动
        t1.start();
        t2.start();
    }
}


2.set数据类型

2.1使用场景:

  • 新的存储需求:存储大量的数据,在查询方面提供更高的效率
  • 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
  • set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值式不允许重复的。也就是只有键没有值的hash
  • set集合数据不重复的特征,依赖set集合hash存储结构特征完成数据过滤与快速查询

业务场景-共同好友

在这里插入图片描述

 2.2set常用命令集合

Redis的Set类似Java中的HashSet,是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis中Set集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

sadd

添加元素,重复元素添加失败,返回0

127.0.0.1:6379> sadd name tony
(integer) 1
127.0.0.1:6379> sadd name hellen
(integer) 1
127.0.0.1:6379> sadd name rose
(integer) 1
127.0.0.1:6379> sadd name rose ##重复了返回0表示失败
(integer) 0

smembers:获取内容

127.0.0.1:6379> smembers name

  1. “hellen”
  2. “rose”
  3. “tony”

spop:随机移除一个

移除并返回集合中的一个随机元素

127.0.0.1:6379> smembers internet
1) "amoeba"
2) "redis"
3) "rabbitmq"
4) "nginx"
127.0.0.1:6379> spop internet
"rabbitmq"
127.0.0.1:6379> spop internet
"nginx"
127.0.0.1:6379> smembers internet
1) "amoeba"
2) "redis"

scard

获取成员个数

127.0.0.1:6379> scard name
(integer) 3

smove :smove "A"集合 "B"集合 A集合中的一个值

移动一个元素到另外一个集合

 sunion:并集

127.0.0.1:6379> sunion internet bigdata
1) "redis"
2) "nginx"
3) "rabbitmq"
4) "amoeba"
5) "hadopp"
6) "spark"

小节面试分析

  • 朋友圈的点赞功能你如何实现?(sadd,srem,smembers,scard)
  • 如何实现一个网站投票统计程序?
  • 你知道微博中的关注如何实现吗?

3.Set实际使用业务场景Demo练习

投票系统Demo

业务描述

在很多系统中设计中,都会有一个活动设计,开启一个活动之前,可以对这个活动的支持力度先进行一个调查,例如基于这个活动设计一个投票系统,例如:

在这里插入图片描述

 代码实现

package com.jt.redis;

import redis.clients.jedis.Jedis;

import java.util.Set;

/**
 * 基于某个活动的投票系统的简易设计
 * 需求:
 * 1)基于用户id对活动进行投票
 * 2)一个用户id只能参与一次投票
 * 3)可以查询投票总数以及参数投票的用户id
 * 设计:
 * 1)数据存储结构:set结构(不允许重复)
 */
public class VoteDemo01 {
    static final String IP="192.168.126.129";
    static final int PORT=6379;
    /**
     * 检查用户是否参与过此活动的投票
     * @param activityId
     * @param userId
     */
    public static Boolean isVote(String activityId,String userId){
         //1.创建jedis对象
        Jedis jedis=new Jedis(IP, PORT);
         //2.检查是否投票
        Boolean flag = jedis.sismember(activityId, userId);
        //3.释放资源
        jedis.close();
         //4.返回结果
        return flag;
    }
    /**
     * 执行投票操作
     * @param activityId
     * @param userId
     */
    public static void doVote(String activityId,String userId){
        //1.创建Jedis对象
        Jedis jedis=new Jedis(IP, PORT);
        //2.执行投票
        jedis.sadd(activityId, userId);
        //3.释放资源
        jedis.close();
    }
    /**
     * 查看活动的总投票数量
     * @param activityId
     */
    public static Long  doGetVotes(String activityId){
        //1.创建Jedis对象
        Jedis jedis=new Jedis(IP, PORT);
        //2.查看活动的投票数
        Long count = jedis.scard(activityId);
        //3.释放资源
        jedis.close();
        //4.返回投票数量
        return count;
    }
    /**
     * 获取参与投票当前活动的用户
     * @param activityId
     */
    public static Set<String> doGetUsers(String activityId){
        //1.创建Jedis对象
        Jedis jedis=new Jedis(IP, PORT);
        //2.查看活动的投票数
        Set<String> smembers = jedis.smembers(activityId);
        //3.释放资源
        jedis.close();
        //4.返回投票数量
        return smembers;
    }

    public static void main(String[] args) {
        //1.定义活动id,用户id
        String activityId="10001";
        String user1="301";
        String user2="302";
        //2.进行投票检查
        Boolean flag=isVote(activityId, user1);
        System.out.println("flag="+flag);
        //3.进行投票
        doVote(activityId, user1);
        doVote(activityId, user2);
        //4.获取投票的总数
        Long aLong = doGetVotes(activityId);
        System.out.println(activityId +"活动的总投票数为 "+aLong);
        //5.获取参与投票的用户
        Set<String> users = doGetUsers(activityId);
        System.out.println("参与"+activityId+"活动的投票用户为"+users);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧冶渃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值