热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android实现评论点赞功能_Redis实现点赞功能模块

之前看了一篇文章,讲redis的应用场景,其中一个应用场景就是实现点赞功能。功能点设计比如发一篇知乎文章就有点赞功能,比如统计某篇文章的点
之前看了一篇文章,讲redis的应用场景,其中一个应用场景就是实现点赞功能。

功能点设计

比如发一篇知乎文章就有点赞功能,比如统计某篇文章的点赞数、用户所有文章的点赞总数,因此设计的点赞功能模块有以下功能点:

  • 某篇文章的点赞数;
  • 用户所有文章的点赞数;
  • 用户点赞的文章;
  • 持久化到MySQL数据库;

数据库设计

  • Redis数据库设计 redis是一个K-V数据库,没有统一的数据结构,针对不同的功能点,设计不同的数据结构类型
  1. 用户某篇文章的点赞数 使用HashMap>数据结构,HashMap中的key为articleId,value为Set,Set中的值为userId;
  2. 用户总的点赞数,使用HashMap数据结构,key为userId,value为记录总的点赞数;
  3. 用户点赞的文章,使用HashMap数据结构,key为userId,value为Set,Set中的值为articleId;
MySQL数据库设计,最主要的两张表,article表和user_like_article表

article表结构

字段值字段类型说明
idvarchar2(24)主键
article_namevarchar2(100)文章内容
contentblob文章内容
total_like_countbigint文章总点赞数

文章总的点赞数需要和Redis中的点赞数进行同步。

user_like_article表结构

字段值字段类型说明
idvarchar(24)主键
user_idbigint用户ID
article_idbigint文章ID

记录用户点赞文章的信息,是一张中间表

说明:表结构设计省略了delete_state、create_timeupdate_time等字段。

流程图

931c86f70bd57442b217f487a4e83f25.png

流程图比较简单,点赞和取消点赞基本实现步骤相同

  1. 参数校验 对入参进行非空校验
  2. 逻辑校验 对于用户点赞,用户不能重复点赞相同的文章,对于取消点赞,用户不能取消为点赞的文章。
  3. 存入Redis 存入的数据主要是文章的点赞数,某篇文章的点赞数,用户点赞的文章
  4. 定时任务 通过定时【1小时执行一次】,从Redis读取数据持久化到MySQL中。

代码功能实现

  • 点赞

public void likeArticle(Long articleId, Long likedUserId, Long likedPostId) {validateParam(articleId, likedUserId, likedPostId); //参数验证logger.info("点赞数据存入redis开始&#xff0c;articleId:{}&#xff0c;likedUserId:{}&#xff0c;likedPostId:{}", articleId, likedUserId, likedPostId);synchronized (this) {//只有未点赞的用户才可以进行点赞likeArticleLogicValidate(articleId, likedUserId, likedPostId);//1.用户总点赞数&#43;1redisTemplate.opsForHash().increment(TOTAL_LIKE_COUNT_KEY, String.valueOf(likedUserId), 1);//2.用户喜欢的文章&#43;1String userLikeResult &#61; (String) redisTemplate.opsForHash().get(USER_LIKE_ARTICLE_KEY, String.valueOf(likedPostId));Set articleIdSet &#61; userLikeResult &#61;&#61; null ? new HashSet<>() : FastjsonUtil.deserializeToSet(userLikeResult, Long.class);articleIdSet.add(articleId);redisTemplate.opsForHash().put(USER_LIKE_ARTICLE_KEY, String.valueOf(likedPostId), FastjsonUtil.serialize(articleIdSet));//3.文章点赞数&#43;1String articleLikedResult &#61; (String) redisTemplate.opsForHash().get(ARTICLE_LIKED_USER_KEY, String.valueOf(articleId));Set likePostIdSet &#61; articleLikedResult &#61;&#61; null ? new HashSet<>() : FastjsonUtil.deserializeToSet(articleLikedResult, Long.class);likePostIdSet.add(likedPostId);redisTemplate.opsForHash().put(ARTICLE_LIKED_USER_KEY, String.valueOf(articleId), FastjsonUtil.serialize(likePostIdSet));logger.info("取消点赞数据存入redis结束&#xff0c;articleId:{}&#xff0c;likedUserId:{}&#xff0c;likedPostId:{}", articleId, likedUserId, likedPostId);}
}

  • 取消点赞

public void unlikeArticle(Long articleId, Long likedUserId, Long likedPostId) {validateParam(articleId, likedUserId, likedPostId); //参数校验logger.info("取消点赞数据存入redis开始&#xff0c;articleId:{}&#xff0c;likedUserId:{}&#xff0c;likedPostId:{}", articleId, likedUserId, likedPostId);//1.用户总点赞数-1synchronized (this) {//只有点赞的用户才可以取消点赞unlikeArticleLogicValidate(articleId, likedUserId, likedPostId);Long totalLikeCount &#61; Long.parseLong((String)redisTemplate.opsForHash().get(TOTAL_LIKE_COUNT_KEY, String.valueOf(likedUserId)));redisTemplate.opsForHash().put(TOTAL_LIKE_COUNT_KEY, String.valueOf(likedUserId), String.valueOf(--totalLikeCount));//2.用户喜欢的文章-1String userLikeResult &#61; (String) redisTemplate.opsForHash().get(USER_LIKE_ARTICLE_KEY, String.valueOf(likedPostId));Set articleIdSet &#61; FastjsonUtil.deserializeToSet(userLikeResult, Long.class);articleIdSet.remove(articleId);redisTemplate.opsForHash().put(USER_LIKE_ARTICLE_KEY, String.valueOf(likedPostId), FastjsonUtil.serialize(articleIdSet));//3.取消用户某篇文章的点赞数String articleLikedResult &#61; (String) redisTemplate.opsForHash().get(ARTICLE_LIKED_USER_KEY, String.valueOf(articleId));Set likePostIdSet &#61; FastjsonUtil.deserializeToSet(articleLikedResult, Long.class);likePostIdSet.remove(likedPostId);redisTemplate.opsForHash().put(ARTICLE_LIKED_USER_KEY, String.valueOf(articleId), FastjsonUtil.serialize(likePostIdSet));}logger.info("取消点赞数据存入redis结束&#xff0c;articleId:{}&#xff0c;likedUserId:{}&#xff0c;likedPostId:{}", articleId, likedUserId, likedPostId);
}

  • 异步落库

&#64;Scheduled(cron &#61; "0 0 0/1 * * ? ")
public void redisDataToMySQL() {logger.info("time:{}&#xff0c;开始执行Redis数据持久化到MySQL任务", LocalDateTime.now().format(formatter));//1.更新文章总的点赞数Map articleCountMap &#61; redisTemplate.opsForHash().entries(ARTICLE_LIKED_USER_KEY);for (Map.Entry entry : articleCountMap.entrySet()) {String articleId &#61; entry.getKey();Set userIdSet &#61; FastjsonUtil.deserializeToSet(entry.getValue(), Long.class);//1.同步某篇文章总的点赞数到MySQLsynchronizeTotalLikeCount(articleId, userIdSet);//2.同步用户喜欢的文章synchronizeUserLikeArticle(articleId, userIdSet);}logger.info("time:{}&#xff0c;结束执行Redis数据持久化到MySQL任务", LocalDateTime.now().format(formatter));
}

说明&#xff1a;

  • 针对存在并发的问题&#xff0c;通过添加synchronize关键字实现
  • 另外还有获取某篇文章的点赞数、用户所有文章的点赞数、用户点赞的文章方法实现&#xff0c;方法实现比较简单不说明&#xff0c;可以在完整代码中找到

目前存在的不足

  • 用户点赞取消点赞方法中&#xff0c;Redis事物没有保证
  • 该应用只适合单机环境&#xff0c;分布式环境下存在并发操作&#xff0c;分布式锁待完成

最后附&#xff1a;欢迎fork与start&#xff0c;如有纰漏欢迎指正

alan-cxh/like_article​github.com
23830644564fc9d61284a1b070614ace.png



推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 如何在php中将mysql查询结果赋值给变量
    本文介绍了在php中将mysql查询结果赋值给变量的方法,包括从mysql表中查询count(学号)并赋值给一个变量,以及如何将sql中查询单条结果赋值给php页面的一个变量。同时还讨论了php调用mysql查询结果到变量的方法,并提供了示例代码。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 在Android中解析Gson解析json数据是很方便快捷的,可以直接将json数据解析成java对象或者集合。使用Gson解析json成对象时,默认将json里对应字段的值解析到java对象里对应字段的属性里面。然而,当我们自己定义的java对象里的属性名与json里的字段名不一样时,我们可以使用@SerializedName注解来将对象里的属性跟json里字段对应值匹配起来。本文介绍了使用@SerializedName注解解析json数据的方法,并给出了具体的使用示例。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
author-avatar
手机用户2502863643
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有