牛客论坛项目中使用到Redis的地方总结

news2025/1/25 9:09:55

在这里插入图片描述

实体分为很多类,实体的确定要通过实体类型和实体id两个属性同时确定。牛客论坛中使用到了3类实体:
在这里插入图片描述

在这里插入图片描述

1 登录

使用到的Redis命令:

set key value // 设置指定key的值为value
get key // 获取指定key的值

1.1 存储/获取验证码

验证码文本,登录前,用户根据验证码图片输入验证码文本,用户提交登录,服务器会将用户输入的验证码文本于缓存在Redis中的验证码文本做字符串比较。

1、将验证码存入Redis

String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);

2、获取验证码

String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);

1.2 存储/获取登录凭证

登录成功后,用户获得登录凭证,里面存储了用户id、凭证过期时间、状态,用于登录和登出功能。

1、存储登录凭证:

String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
redisTemplate.opsForValue().set(redisKey, loginTicket);

2、获取登录凭证:

String redisKey = RedisKeyUtil.getTicketKey(ticket);
LoginTicket loginTicket = (LoginTicket) redisTemplate.opsForValue().get(redisKey);

2 点赞

使用到的Redis命令:

// 以下是集合的命令
sadd key element [element …] // 向集合key添加一个或多个元素
srem key element [element …] // 移除集合key中的一个或多个元素
sismember key memeber // 用于判断元素 member是否集合的成员。
scard key  // 获取集合的成员数

// 以下是字符串的命令
incr key	//将key中储存的字符串数值增一
decr key	//将key中储存的字符串数值减一
get key 	// 获取字符串数值

2.1 用户给实体点赞 / 取消点赞

public void like(int userId, int entityType, int entityId, int entityUserId) {
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
            String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId);

            boolean isMember = operations.opsForSet().isMember(entityLikeKey, userId);

            // 开始一个Redis事务
            operations.multi();

            if (isMember) {
                operations.opsForSet().remove(entityLikeKey, userId);
                operations.opsForValue().decrement(userLikeKey);
            } else {
                operations.opsForSet().add(entityLikeKey, userId);
                operations.opsForValue().increment(userLikeKey);
            }

            // 执行Redis事务,并返回结果
            return operations.exec();
        }
    });
}

2.2 查询某实体点赞的数量

public long findEntityLikeCount(int entityType, int entityId) {
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().size(entityLikeKey);
    }

2.3 查询某人对某实体的点赞状态

public int findEntityLikeStatus(int userId, int entityType, int entityId) {
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().isMember(entityLikeKey, userId) ? 1 : 0;
    }

2.4 查询某个用户获得的赞

public int findUserLikeCount(int userId) {
        String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);
        Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey);
        return count == null ? 0 : count.intValue();
    }

3 关注

使用到的Redis命令

zadd key score member [score member …]	// 向有序集合key添加一个或多个成员,或者更新已存在成员的分数
zrem key member [member …]	// 移除有序集合key中的一个或多个成员
zcard key	// 获取有序集合key的成员数
zscore key member	//返回有序集合key中,成员member的分数
zrange key start end [withscores]	//返回有序集合key中,指定区间内的成员
zrevrange key start end [withscores]	//返回有序集合key中,指定区间内的成员,通过索引,分数从高到低

3.1 用户关注某个实体

某个用户关注的实体,有序集合里面存放的是entity_id,分数是时间,实体类型在key里。
可以关注某个用户,entity_type=3
可以关注某个帖子,entity_type=1
可以关注某条评论,entity_type=2

public void follow(int userId, int entityType, int entityId) {
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
            String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);

            operations.multi();

            operations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
            operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());

            return operations.exec();
        }
    });
}

3.2 用户取消关注

public void unfollow(int userId, int entityType, int entityId) {
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
            String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);

            operations.multi();

            operations.opsForZSet().remove(followeeKey, entityId);
            operations.opsForZSet().remove(followerKey, userId);

            return operations.exec();
        }
    });
}

3.3 查询关注的实体的数量

public long findFolloweeCount(int userId, int entityType) {
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
    return redisTemplate.opsForZSet().zCard(followeeKey);
}

3.4 查询实体的粉丝的数量

public long findFollowerCount(int entityType, int entityId) {
    String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
    return redisTemplate.opsForZSet().zCard(followerKey);
}

3.5 查询当前用户是否已关注该实体

由于有序集合没有类似集合那样sismember key memeber // 用于判断元素 member是否集合的成员。
所以只能用获取分数,判断分数是不是为空

public boolean hasFollowed(int userId, int entityType, int entityId) {
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
    return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
}

3.6 查询某用户关注的人(关注列表) ,分页展示

public List<Map<String, Object>> findFollowees(int userId, int offset, int limit) {
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);

3.7 查询某用户的粉丝 (粉丝列表),分页展示

public List<Map<String, Object>> findFollowers(int userId, int offset, int limit) {
    String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);

4 网站数据统计

使用到的Redis命令:

// 以下是HyperLogLog的命令
pfadd key element [element ...] // 向HyperLogLog添加元素
pfcount key [key ..]  // 计算独立用户数
pfmerge destkey sourcekey [sourcekey ...] // 求出多个HyperLogLog的并集并复制给destkey

// 以下是bitmaps的命令
setbit key offset value // 设置第offset个位置的值
getbit key offset   // 获取第offset个位置的值
bitop or destkey key [key ...] //多个bitmaps做Or运算
bitcount key [start end] // 获取bitmaps指定范围值为1的个数

4.1 统计独立访客

独立访客,union
1、将指定的IP计入UV

public void recordUV(String ip) {
    String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));
    redisTemplate.opsForHyperLogLog().add(redisKey, ip);
}

2、统计指定日期范围内的UV

// 合并这些数据
String redisKey = RedisKeyUtil.getUVKey(df.format(start), df.format(end));
redisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());

// 返回统计的结果
return redisTemplate.opsForHyperLogLog().size(redisKey);

4.2 统计日活跃用户

日活跃用户,or位运算
1、 将指定用户计入DAU

public void recordDAU(int userId) {
    String redisKey = RedisKeyUtil.getDAUKey(df.format(new Date()));
    redisTemplate.opsForValue().setBit(redisKey, userId, true);
}

2、 统计指定日期范围内的DAU

// 进行OR运算
return (long) redisTemplate.execute(new RedisCallback() {
    @Override
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
        String redisKey = RedisKeyUtil.getDAUKey(df.format(start), df.format(end));
        connection.bitOp(RedisStringCommands.BitOperation.OR,
                redisKey.getBytes(), keyList.toArray(new byte[0][0]));
        return connection.bitCount(redisKey.getBytes());
    }
});

5 缓存设计

使用到的Redis命令:

set key value // 设置指定key的值为value
get key // 获取指定key的值
del key [key …]	 // 删除一个或多个key

5.1 优先从缓存中取值

private User getCache(int userId) {
    String redisKey = RedisKeyUtil.getUserKey(userId);
    return (User) redisTemplate.opsForValue().get(redisKey);
}

5.2 取不到时初始化缓存数据

private User initCache(int userId) {
    User user = userMapper.selectById(userId);
    String redisKey = RedisKeyUtil.getUserKey(userId);
    redisTemplate.opsForValue().set(redisKey, user, 3600, TimeUnit.SECONDS);
    return user;
}

5.3 数据变更时清除缓存数据

private void clearCache(int userId) {
    String redisKey = RedisKeyUtil.getUserKey(userId);
    redisTemplate.delete(redisKey);
}

6 热帖排行

使用到的Redis命令

sadd key element [element …]	// 向集合key添加一个或多个元素
	spop key	// 移除并返回集合中的一个随机元素

里面存放的是帖子id,用于启动定时任务计算帖子分数,有哪些帖子要计算分数。

6.1 记录要计算分数的帖子

// 
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, postId);

## 6.1 获取所有要计算分数的帖子

while (operations.size() > 0) {
    this.refresh((Integer) operations.pop());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1575817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【iOS】UITableView性能优化

文章目录 前言一、优化的本质二、卡顿产生原因三、CPU层面优化1.使用轻量级对象2.cellForRowAtIndexPath方法中不要做耗时操作3.UITableView的复用机制4.提前计算好布局了解tableView代理方法执行顺序cell高度计算rowHeightestimatedRowHeight 高度计算进行时机rowHeight计算时…

无参数绕过RCE

一.什么是无参数 顾名思义&#xff0c;就是只使用函数&#xff0c;且函数不能带有参数&#xff0c;这里有种种限制&#xff1a;比如我们选择的函数必须能接受其括号内函数的返回值&#xff1b;使用的函数规定必须参数为空或者为一个参数等 无参数题目特征 if(; preg_replace…

这就是AI眼中的物理世界:OpenAI Sora音乐短片《Worldweight》和超现实影片《气球人》

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

Java8关于Function接口

Java学习-Function接口 1 函数式接口简介和学习地址2 两种常见的函数式接口2.1 Runnable&#xff1a;执行接口&#xff0c;不接收参数&#xff0c;也无返回结果。2.2 Consumer&#xff1a;作为消费接口&#xff0c;接收一个参数&#xff0c;无返回结果。 3 初识3.1 定义Functio…

JVM从1%到99%【精选】-初步认识

目录 &#x1f95e;1.什么是JVM &#x1f37f;2.JVM的功能 &#x1f953;3.常见的JVM &#x1f32d;4.JVM的位置 &#x1f9c2;5.JVM的整体结构 &#x1f383;6.JVM的生命周期 &#x1f388;7.JVM的架构模型 1.什么是JVM JVM本质上是一个运行在计算机上的程序,他的职责…

WPS快速将插入Excle数据插入Word

前置条件&#xff1a; 一张有标题、数据的excle表格word中的表格与excle表格标题对应或包含电脑已经安装WPS软件 第一步、根据word模板设计excle模板&#xff0c;标头对应 第二步、word上面选【引用】--【邮件】&#xff0c;选打开数据源&#xff0c;找到excle文件&#xff0c;…

vscode-插件开发-hello world-创建初始模板

参考vscode官方示例&#xff1a;如何创建你的第一个插件开发项目模板的步骤进行了下文操作。 目录 前言1.环境配置全局安装 yo, generator-code 2. 新建一个插件项目模板问题1: F5 按键无法启动launch.json调试(解决)问题1 描述:问题1: 找错误问题1: 可行的解决方案 3. 开发插…

Linux部署sonarqube+Gogs+Jenkins(二)

Linux部署sonarqubeGogsJenkins 一、Jenkins执行任务1、使用源码管理拉取代码-操作步骤第一步&#xff1a;确认环境&#xff0c;进入到Jenkins【系统管理】—>【全局工具配置】—>【Git】为下图显示&#xff1b;第二步&#xff1a;构建项目时对项目的源码管理选择 Git第三…

基于R语言地理加权回归、主成份分析、判别分析等空间异质性数据分析教程

原文链接&#xff1a;基于R语言地理加权回归、主成份分析、判别分析等空间异质性数据分析教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247600473&idx6&sn431e9408a42862d29fe4f4ef7703595b&chksmfa8208becdf581a820d9479d2aa61b88e96612c4ab72b0…

系统架构评估_2.SAAM方法

SAAM&#xff08;Scenarios-based Architecture Analysis Method&#xff09;是卡耐基梅隆大学软件工程研究所&#xff08;SEI at CMU&#xff09;的Kazman等人于1983年提出的一种非功能质量属性的架构分析方法&#xff0c;是最早形成文档并得到广泛使用的软件架构分析方法。最…

设计方案:914-基于64路AD的DBF波束形成硬件

一、硬件概述 &#xff24;&#xff22;&#xff26;技术的实现全部是在数字域实现&#xff0c;然而天线阵列接收的信号经过多次混频后得到的中频信号是模拟信号&#xff0c;实现&#xff24;&#xff22;&#xff26;处理并充分发挥&#xff24;&#xff22;&…

pdf操作器(图片转文字、PDF转word、PDF拆分、图片jpg、png互转)

pdf操作器&#xff08;不用联网图片转文字、PDF转word、PDF拆分、图片jpg、png互转&#xff09;介绍目前该软件实现了以下功能 pdf转wordpdf拆分图片&#xff0c;图片导出在桌面的一个文件夹里图片合并为pdf压缩、转换图片格式&#xff08;jpg和png&#xff09;OCR图片转文字&…

如何在社交媒体中使用增强现实来提高客户参与度?

目录 1. 增强现实在社交媒体中的应用是如何发展的 2. 社交媒体营销和广告中的增强现实 3. 社交媒体上的增强现实滤镜和镜头 4. 社交媒体平台上的增强现实购物 5. 利用社交媒体的增强现实事件和品牌激活 6. 增强现实在社交媒体中的未来是什么 7. 社交媒体中的增强现实常见…

xilinx 7系列fpga上电配置

一、前言 Xilinx FPGA通过加载比特流到内部存储单元来进行配置。 Xilinx FPGA存在两种数据配置路径&#xff0c;一种是满足最小引脚需求的串行路径&#xff0c;一种是可用8位、16位或32位来连接到行业的高性能通用接口&#xff0c;如处理器&#xff0c;8位或者16位并行的闪存…

轻量化日志中心 Grafana Loki

需要集中的日志系统的原因 目前现状,每个服务生产上有三台,定位生产问题,需要连上一台机器,然后使用 cd / tail / less / grep / sed / awk 等 linux命令去日志里查找故障原因。如果在这台机器没搜索到线索,就去另外两台机器上查日志。 但在分布式系统中,众多服务分散部…

链路代价信息、链路状态信息(链路状态通告LSA)

链路代价信息"link cost information" 通常指的是**在网络中&#xff0c;数据包从一个节点传输到另一个节点所需承担的“成本”或者“开销”&#xff0c;这个概念常用于路由算法和网络设计中**。以下是一些关键要点&#xff1a; 1. **路径开销**&#xff1a;路径开…

吹爆!遥感高光谱分类(Python)

目录 一、数据集下载 二、安装包 三、数据处理 四、模型训练 五、模型推理 六、踩坑记录 一、数据集下载 Hyperspectral Remote Sensing Scenes - Grupo de Inteligencia Computacional (GIC) (ehu.eus) Installing SPy — Spectral Python 0.21 documentation 二、安装…

企业计算机服务器中了locked勒索病毒怎么办,locked勒索病毒解密流程步骤

网络技术的不断发展为企业的生产运营提供了极大便利&#xff0c;也让企业的生产效率大大提高&#xff0c;但网络是一把双刃剑&#xff0c;给给企业的数据安全问题带来严重威胁。近期&#xff0c;云天数据恢复中心接到浙江某商贸公司的求助&#xff0c;企业计算机服务器遭到了lo…

HBase详解(2)

HBase 结构 HRegion 概述 在HBase中&#xff0c;会从行键方向上对表来进行切分&#xff0c;切分出来的每一个结构称之为是一个HRegion 切分之后&#xff0c;每一个HRegion会交给某一个HRegionServer来进行管理。HRegionServer是HBase的从节点&#xff0c;每一个HRegionServ…

阿里云乱扣费故障,技术堪忧

2024年4月3日&#xff0c;距离2023年11月的故障没有多久&#xff0c;阿里云又出现乱扣费故障&#xff0c;导致账号欠费3000多&#xff0c;oss&#xff0c;块存储&#xff0c;cdn等所有后付费服务停止工作&#xff0c;不知道这个故障能算什么级别的。 凌晨1点多&#xff0c;收到…