点赞功能:用 MySQL 还是 Redis?

点赞功能真的有必要上 Redis 吗?(Mongo、MySQL、Redis、MQ 实测性能对比) 除了单表操作比较耗时外,对于中小型项目而言,频繁的读写操作场景,使用 mongo 就够用了. 甚至都不用上 mq,更甚至有的场景下 redis 性能还不如 mongo... 阅读详情

这是最近面试时被问到的1道面试题,本篇博客对此问题进行总结分享。

1. 新手常犯的错误

可能很多新手(包括当年的我,哈哈)第一时间想到的写法是下面这样的:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    for (String platform : platformList) {
        if (platform.equals("博客园")) {
            platformList.remove(platform);
        }
    }

    System.out.println(platformList);
}

然后满怀信心的去运行,结果竟然抛
java.util.ConcurrentModificationException异常了,翻译成中文就是:并发修改异常。

点赞功能:用 MySQL 还是 Redis?

是不是很懵,心想这是为什么呢?

让我们首先看下上面这段代码生成的字节码,如下所示:

点赞功能:用 MySQL 还是 Redis?

由此可以看出,foreach循环在实际执行时,其实使用的是Iterator,使用的核心方法是hasnext()和next()。

然后再来看下ArrayList类的Iterator是如何实现的呢?

点赞功能:用 MySQL 还是 Redis?

可以看出,调用next()方法获取下一个元素时,第一行代码就是调用了checkForComodification();,而该方法的核心逻辑就是比较modCount和expectedModCount这2个变量的值。

在上面的例子中,刚开始modCount和expectedModCount的值都为3,所以第1次获取元素"博客园"是没问题的,但是当执行完下面这行代码时:

platformList.remove(platform);

modCount的值就被修改成了4。

点赞功能:用 MySQL 还是 Redis?

所以在第2次获取元素时,modCount和expectedModCount的值就不相等了,所以抛出了
java.util.ConcurrentModificationException异常。

点赞功能:用 MySQL 还是 Redis?

既然不能使用foreach来实现,那么我们该如何实现呢?

主要有以下3种方法:

  • 使用Iterator的remove()方法
  • 使用for循环正序遍历
  • 使用for循环倒序遍历

接下来一一讲解。

2. 使用Iterator的remove()方法

使用Iterator的remove()方法的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    Iterator<String> iterator = platformList.iterator();
    while (iterator.hasNext()) {
        String platform = iterator.next();
        if (platform.equals("博客园")) {
            iterator.remove();
        }
    }

    System.out.println(platformList);
}

输出结果为:

[优快云, 掘金]

为什么使用iterator.remove();就可以呢?让我们看下它的源码:

点赞功能:用 MySQL 还是 Redis?

可以看出,每次删除一个元素,都会将modCount的值重新赋值给expectedModCount,这样2个变量就相等了,不会触发
java.util.ConcurrentModificationException异常。更多面试题,欢迎关注公众号 Java面试题精选

3. 使用for循环正序遍历

使用for循环正序遍历的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    for (int i = 0; i < platformList.size(); i++) {
        String item = platformList.get(i);

        if (item.equals("博客园")) {
            platformList.remove(i);
            i = i - 1;
        }
    }

    System.out.println(platformList);
}

这种实现方式比较好理解,就是通过数组的下标来删除,不过有个注意事项就是删除元素后,要修正下下标的值:

i = i - 1;

为什么要修正下标的值呢?因为刚开始元素的下标是这样的:

点赞功能:用 MySQL 还是 Redis?

第1次循环将元素"博客园"删除后,元素的下标变成了下面这样:

点赞功能:用 MySQL 还是 Redis?

第2次循环时i的值为1,也就是取到了元素”掘金“,这样就导致元素"优快云"被跳过检查了,所以删除完元素后,我们要修正下下标,这也是上面代码中i = i - 1;的用途。更多面试问题可以关注微信订阅号码匠笔记回复面试获取

4. 使用for循环倒序遍历

使用for循环倒序遍历的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    for (int i = platformList.size() - 1; i >= 0; i--) {
        String item = platformList.get(i);

        if (item.equals("掘金")) {
            platformList.remove(i);
        }
    }

    System.out.println(platformList);
}

这种实现方式和使用for循环正序遍历类似,不过不用再修正下标,因为刚开始元素的下标是这样的:

点赞功能:用 MySQL 还是 Redis?

第1次循环将元素"掘金"删除后,元素的下标变成了下面这样:

点赞功能:用 MySQL 还是 Redis?

第2次循环时i的值为1,也就是取到了元素”优快云“,不会导致跳过元素,所以不需要修正下标。

 

所以在第2次获取元素时,modCount和expectedModCount的值就不相等了,所以抛出了
java.util.ConcurrentModificationException异常。

点赞功能:用 MySQL 还是 Redis?

既然不能使用foreach来实现,那么我们该如何实现呢?

主要有以下3种方法:

  • 使用Iterator的remove()方法
  • 使用for循环正序遍历
  • 使用for循环倒序遍历

接下来一一讲解。

5. 使用Iterator的remove()方法

使用Iterator的remove()方法的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    Iterator<String> iterator = platformList.iterator();
    while (iterator.hasNext()) {
        String platform = iterator.next();
        if (platform.equals("博客园")) {
            iterator.remove();
        }
    }

    System.out.println(platformList);
}

输出结果为:

[优快云, 掘金]

为什么使用iterator.remove();就可以呢?让我们看下它的源码:

点赞功能:用 MySQL 还是 Redis?

可以看出,每次删除一个元素,都会将modCount的值重新赋值给expectedModCount,这样2个变量就相等了,不会触发
java.util.ConcurrentModificationException异常。更多面试题,欢迎关注公众号 Java面试题精选

6. 使用for循环正序遍历

使用for循环正序遍历的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    for (int i = 0; i < platformList.size(); i++) {
        String item = platformList.get(i);

        if (item.equals("博客园")) {
            platformList.remove(i);
            i = i - 1;
        }
    }

    System.out.println(platformList);
}

这种实现方式比较好理解,就是通过数组的下标来删除,不过有个注意事项就是删除元素后,要修正下下标的值:

i = i - 1;

为什么要修正下标的值呢?因为刚开始元素的下标是这样的:

点赞功能:用 MySQL 还是 Redis?

第1次循环将元素"博客园"删除后,元素的下标变成了下面这样:

点赞功能:用 MySQL 还是 Redis?

第2次循环时i的值为1,也就是取到了元素”掘金“,这样就导致元素"优快云"被跳过检查了,所以删除完元素后,我们要修正下下标,这也是上面代码中i = i - 1;的用途。更多面试问题可以关注微信订阅号码匠笔记回复面试获取

7. 使用for循环倒序遍历

使用for循环倒序遍历的实现方式如下所示:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("博客园");
    platformList.add("优快云");
    platformList.add("掘金");

    for (int i = platformList.size() - 1; i >= 0; i--) {
        String item = platformList.get(i);

        if (item.equals("掘金")) {
            platformList.remove(i);
        }
    }

    System.out.println(platformList);
}

这种实现方式和使用for循环正序遍历类似,不过不用再修正下标,因为刚开始元素的下标是这样的:

点赞功能:用 MySQL 还是 Redis?

第1次循环将元素"掘金"删除后,元素的下标变成了下面这样:

点赞功能:用 MySQL 还是 Redis?

第2次循环时i的值为1,也就是取到了元素”优快云“,不会导致跳过元素,所以不需要修正下标。

接入 AI 之后,为什么测试和排障还是没有真正变快? 如果你们准备做平台型 AI,不要先从聊天入口开始想。先把真实数据采上来;再把链路、版本、快照、报告这些核心对象建稳;再把历史沉淀、反馈、检索能力补齐;最后再让 AI 围绕这些对象去工作。这样做出来的 AI,才更容易从“看起来聪明”走向“真正省时间”。 阅读详情

相关推荐

不用买显示器!用USBMMID虚拟显示器软件在Win10上扩展4个屏幕(保姆级教程)

本文提供了一份详细的保姆级教程,指导用户如何在Windows 10系统上,无需购买额外硬件,通过USBMMID虚拟显示器软件扩展出多达4个虚拟屏幕。文章深入解析了虚拟显示器的核心原理,并基于微软IDD框架,手把手教学从软件获取、环境检查到安装配置的全过程,帮助开发者和多任务用户构建高效、免费的虚拟多屏工作站,实现生产力的飞跃。

backprop5master的博客 661

MongoDB

课程目标: 理解MongoDB的业务场景,熟悉MongoDB的简介、特点和体系结构、数据类型等。 能够在windows和Linux下安装和启动MongoDB、图形化界面Compass的安装使用。 掌握MongoDB基本常用命令实现数据的CRUD。 掌握MongoDB的索引类型、索引管理、执行计划。 使用Spring Data MongoDB完成文章评论业务的开发。 1.MongoDB相关概念 业务应用场景 传统的关系型数据库(如MYSQL),在数据操作的“三高”需求以及应对web2.0的网站需

qq_41988770的博客 817

ThinkBook 16 2024 Ubuntu驱动全攻略:从无线网卡到触控板

本文详细介绍了ThinkBook 16 2024在Ubuntu系统下的驱动问题解决方案,涵盖无线网卡、蓝牙、显卡和触控板等关键硬件的驱动修复步骤。通过具体命令和配置指南,帮助用户快速解决兼容性问题,提升Ubuntu在ThinkBook上的使用体验。

weixin_29200741的博客 830

基于redis实现的点赞功能设计

点赞是我们现在经常见到的一个效果,如朋友圈、微博都有点赞的效果,下面这篇文章主要跟大家分享了基于 redis实现的点赞功能设计思路的相关资料,文中介绍的非常详细,对大家实现点赞功能具有一定的参考学习价 值,需要的朋友们下面来一起看看吧。 前言 点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到re...

happypX的博客 3903

RealSense D455启动教程

RealSense D455启动教程 修改rs_camera.launch

每天进步一点点 2419

Android HWC硬件合成器实战:从SurfaceFlinger到显示驱动的完整流程解析

本文深入解析Android HWC硬件合成器从SurfaceFlinger到显示驱动的完整流程,揭示HWC如何优化图形性能并降低功耗。通过实战案例和调试技巧,帮助开发者掌握硬件加速的图层混合技术,提升移动设备的显示效率。

gaochao的博客 494

Springboot 使用redis检测浏览量,评论量,点赞量的变化并完成与mysql的交互(有具体实现,有具体需求)

Springboot 使用redis检测浏览量,评论量,点赞量的变化并完成与mysql的交互(有具体实现,有具体需求) 1浏览量增加 2评论量增加 3点赞量增加与减少 4 新增文章时将新的数据写入redis 5 删除文章时将数据从Redis中删除 6还有redis初始化的时候从mysql中读取数据 7销毁的时候将数据写入mySQL数据库,或者隔一段时间将数据写入数据库

qq_53679247的博客 3484

别再为多相机标定头疼了!用VisionMaster统一坐标系的保姆级教程

本文详细介绍了使用VisionMaster平台解决多相机视觉系统中坐标系统一问题的完整流程。从标定板选择到N点标定,再到实战演练,提供了从原理到落地的全方位指导,帮助工程师高效解决多相机定位引导中的坐标偏差问题。

weixin_38168322的博客 635

点赞模块设计:Redis缓存 + 定时写入数据库实现高性能点赞功能

本文基于 SpringCloud, 用户发起点赞、取消点赞后先存入 Redis 中,再每隔两小时从 Redis 读取点赞数据写入数据库中做持久化存储。 点赞功能在很多系统中都有,但别看功能小,想要做好需要考虑的东西还挺多的。 点赞、取消点赞是高频次的操作,若每次都读写数据库,大量的操作会影响数据库性能,所以需要做缓存。 至于多久从 Redis 取一次数据存到数据库中,根据项目的实际情况定吧,这里暂时设了一个小时。 项目需求需要查看都谁点赞了,所以要存储每个点赞的点赞人、被点赞人,不能简单的做计数。 文章分四

星之宇的博客 2794

从零开始,手把手教你用RTL代码设计一个简单的8位CPU(附状态图与ALU设计)

本文详细介绍了如何从零开始设计一个简单的8位CPU,包括状态机设计、ALU实现与RTL编码实战。通过具体的指令集分析、状态图设计和Verilog代码示例,帮助读者深入理解CPU工作原理,并掌握RTL代码编写技巧。特别适合计算机系统学习者和硬件设计爱好者。

weixin_30847063的博客 320

Rasa Core开发指南

文章目录1. Rasa Core简介1.1 Rasa Core消息处理流程1.2 安装Rasa Core2. Dialogue模型训练2.1 Story样本数据2.2 Domain2.2.0 intents2.2.1 actions2.2.2 templates2.2.3 entities2.2.4 slots3 .训练和使用对话模型3.1 训练对话模型3.2 使用对话模型4. 搭建CustomA...

老蒋也疯狂 1万+

点赞功能:用 MySQL 还是 Redis ?

点赞功能是目前app开发基本的功能今天我们就来聊聊 点赞、评论、收藏等这些场景的db数据库设计问题,1. 我们先来看看场景的需求:a. 显示点赞数量b. 判断用户是否点过赞,用于去重,必须的判断c. 显示个人点赞列表,一般在用户中心d. 显示文章点赞列表我们先看一下头条和微博的例子头条的点赞微博的点赞这两个都是具有顶级流量的,后端肯定有复杂的架构,我们今天只谈大众化的方案。2....

java_zdc的博客 503

华为用自研的MetaERP替换全球顶级的SAP ERP系统,其难度与风险远超一次普通的技术升级,它是一场战略级的、涉及业务筋骨的系统性工程

华为成功用自研MetaERP替换SAP系统,这是一项极具挑战的战略工程。面临四大难度:业务复杂度高(170多国业务)、数据迁移量大(20年历史数据)、技术集成复杂(重构生态系统)、人员适应周期长。同时伴随四大风险:业务中断、数据失真、成本超支、供应链协同问题。华为成功的关键在于:生存压力驱动的战略决心、强大的软件研发能力、以自身业务为试验场、分步实施策略。这一案例证明中国企业能攻克高端软件壁垒,但对大多数企业而言,核心系统替换需谨慎评估风险,建议采用渐进式替代策略。

金牌架构师 535

点赞功能背后的数据存储:MySQL还是Redis?

点赞功能是目前app开发基本的功能今天我们就来聊聊点赞、评论、收藏等这些场景的db数据库设计问题~我们先看一下头条和微博的例子这两个都是具有顶级流量的,后端肯定有复杂的架构,我们今天只谈大众化的方案。2.1 mysql方案mysql方案, 随着nosql的流行,大数据的持续热点,但是mysql仍然不可替代,对于大多数的中小项目,低于千万级的数据量,采用mysql分表+cache,是完全可以胜任的,而且稳定性是其他方案无可比拟的:常用的查询:查询用户点赞过的文章 select post_id from sta

Reische的博客 2203

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

mysql 查询列表是否关注_点赞功能:用 MySQL 还是 Redis ?

点击上方Java后端,选择设为星标优质文章,及时送达作者:一起web编程链接:toutiao.com/i6825148720728769028点赞功能是目前app开发基本的功能今天我们就来聊聊 点赞、评论、收藏等这些场景的db数据库设计问题,1. 我们先来看看场景的需求:a. 显示点赞数量b. 判断用户是否点过赞,用于去重,必须的判断c. 显示个人点赞列表,一般在用户中心d. 显示文...

weixin_39782545的博客 326

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

mysql 去重_点赞功能:用 MySQL 还是 Redis?

优质文章,及时送达作者:一起web编程链接:toutiao.com/i6825148720728769028点赞功能是目前app开发基本的功能今天我们就来聊聊 点赞、评论、收藏等这些场景的db数据库设计问题,1. 我们先来看看场景的需求:a. 显示点赞数量b. 判断用户是否点过赞,用于去重,必须的判断c. 显示个人点赞列表,一般在用户中心d. 显示文章点赞列表我们先看一下头条和微博的例子头条的点赞...

weixin_39635459的博客 105

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

实战篇:点赞功能,用 MySQL 还是 Redis 好 ?

点击上方蓝色“程序猿DD”,选择“设为星标”回复“资源”获取独家整理的学习资料!作者 |一起web编程来源 |toutiao.com/i6825148720728769028点赞功能...

程序猿DD 731

点赞用redis还是mysql_GitHub - wangwenfan/dianzan: php、mysql和redis实现的点赞功能

dianzanmysql和redis实现的点赞功能点赞其实是个很有意思的功能,普通的mysql也可以实现,但是遇到高并发性能上不是很好。目前我觉得比较好的方式是用Redis作缓存来实现,从而减轻数据库的负担。下面这张图用来描述下我实现的思路。redis中有一个post_set的集合记录所有文章ID,每接受到一次请求,就sadd到post_Set。post_user_like_set_{$PID}集...

weixin_42525353的博客 174

mysql去重_点赞功能:用 MySQL 还是 Redis ?

点赞功能是目前app开发基本的功能今天我们就来聊聊 点赞、评论、收藏等这些场景的db数据库设计问题,1. 我们先来看看场景的需求:a. 显示点赞数量b. 判断用户是否点过赞,用于去重,必须的判断c. 显示个人点赞列表,一般在用户中心d. 显示文章点赞列表我们先看一下头条和微博的例子头条的点赞微博的点赞这两个都是具有顶级流量的,后端肯定有复杂的架构,我们今天只谈大众化的方案。2.1 mysql方案m...

weixin_39820244的博客 127

点赞与收藏功能的数据一致性设计:MySQL 与 Redis 的协同实践

第一次:成功第二次:500第三次:500第四次:500“这个请求是不是第一次执行?而是:“执行完成以后,最终状态是不是正确?这就是幂等设计。+1-1重复请求并发请求幂等事务计数器缓存数据一致性│↓数据库唯一索引│↓OnConflict│↓判断是否真正变更│↓MySQL 原子更新│↓事务提交│↓查询数据库真实值│↓Redis SET 真实值│↓Redis 负责读取第一,MySQL 是最终数据源,数据正确性不能依赖 Redis。

2401_82882804的博客 209

基于redis的点赞功能设计

  前言 点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。 直接写入Mysql 直接写入Mysql是最简单的做法。 做两个表即可, post_like 记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到; ...

weixin_34406086的博客 2439

PHP+Redis 实例【一】点赞 + 热度 上篇

前言 点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql(写了几百行的代码都还没写完,有毒)啦 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。 我这里所讲的功能都是基于我之前的项目去说的,所以有些地方可以不用管的,我主要是记录这个功能的实现思路,当你理解了,基本想用什么鬼语言写都一样的。 直接...

黑白相间... 956

基于redis的点赞功能设计(张高伟)

前言 点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。 直接写入Mysql 直接写入Mysql是最简单的做法。 做两个表即可, post_like 记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到;

qq_36663951的博客 5488

mysql redis 点赞_基于redis实现的点赞功能设计思路详解

前言点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。直接写入Mysql直接写入Mysql是最简单的做法。做两个表即可,1、post_like记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到;2、user_like_post记录用户...

weixin_35135418的博客 707

新浪微博「点赞功能」数据库如何设计的?

刚在北大学长的《系统架构设计》讲座上听到这部分内容,觉得还蛮有意思的,这里简单交流一下 【点赞功能】的基本设计思路分两种: mysql直接落地存储; 利用点赞的业务特征来扔到redis中,然后离线刷回mysql 一、mysql方案 对于大多数中小型项目,低于千万级并发的数据,基本可以用mysql分表+cache完成。 这种方法只要做两个表就可以了: 1、记录文章被点赞的次数,有多少人点过赞 2、记录哪些文章被点赞过 常用的查询有: 查询用户点赞过的文章 select post_id from star

九章算法的博客 6720
上一篇: Java实习生一般进公司去做什么呢?
下一篇: 如此Fun的代码注释,原来程序员都是段子手
Javaesandyou
博客等级 码龄5年 742粉丝 563原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值