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

高性能点赞功能实现:Redis缓存+定时任务
本文介绍了如何使用Redis缓存和定时任务实现高性能的点赞功能。首先,详细讲述了Redis的安装、与SpringBoot项目的整合以及数据结构类型。接着,讨论了点赞数据在Redis中的存储格式,选择Hash结构并解释了原因。然后,提到了数据库设计和操作。最后,介绍了如何通过Quartz开启定时任务,将Redis中的点赞数据持久化到数据库中。

我是猿人,一个热爱技术、热爱编程的IT猿。技术是开源的,知识是共享的!

写作是对自己学习的总结和记录,如果您对 Java、分布式、微服务、中间件、Spring Boot、Spring Cloud等技术感兴趣,可以关注我的动态,我们一起学习,一起成长!

用知识改变命运,让家人过上更好的生活,互联网人一家亲!

---公众号猿码天地

Java知识学堂https://gitee.com/zhangbw666/it-knowledge

你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。——《写给程序员朋友》 

作者:solocoder

juejin.im/post/5bdc257e6fb9a049ba410098

本文基于 SpringCloud, 用户发起点赞、取消点赞后先存入 Redis 中,再每隔两小时从 Redis 读取点赞数据写入数据库中做持久化存储。

点赞功能在很多系统中都有,但别看功能小,想要做好需要考虑的东西还挺多的。

点赞、取消点赞是高频次的操作,若每次都读写数据库,大量的操作会影响数据库性能,所以需要做缓存。

至于多久从 Redis 取一次数据存到数据库中,根据项目的实际情况定吧,我是暂时设了两个小时。

项目需求需要查看都谁点赞了,所以要存储每个点赞的点赞人、被点赞人,不能简单的做计数。

文章分四部分介绍:

  • Redis 缓存设计及实现

  • 数据库设计

  • 数据库操作

  • 开启定时任务持久化存储到数据库

一、Redis 缓存设计及实现

1.1 Redis 安装及运行

Redis 安装请自行查阅相关教程。

说下Docker 安装运行 Redis

docker run -d -p 6379:6379 redis:4.0.8

如果已经安装了 Redis,打开命令行,输入启动 Redis 的命令

redis-server

1.2 Redis 与 SpringBoot 项目的整合

1.在 pom.xml 中引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.在启动类上添加注释 @EnableCaching

@SpringBootApplication
@EnableDiscoveryClient
@EnableSwagger2
@EnableFeignClients(basePackages = "com.solo.coderiver.project.client")
@EnableCaching
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

3.编写 Redis 配置类 RedisConfig

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.net.UnknownHostException;


@Configuration
public class RedisConfig {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }


    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

至此 Redis 在 SpringBoot 项目中的配置已经完成,可以愉快的使用了。

1.3 Redis 的数据结构类型

Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。

下面来对这5种数据结构类型作简单的介绍:

1.4 点赞数据在 Redis 中的存储格式

用 Redis 存储两种数据,一种是记录点赞人、被点赞人、点赞状态的数据,另一种是每个用户被点赞了多少次,做个简单的计数。

由于需要记录点赞人和被点赞人,还有点赞状态(点赞、取消点赞),还要固定时间间隔取出 Redis 中所有点赞数据,分析了下 Redis 数据格式中 Hash 最合适。

因为 Hash 里的数据都是存在一个键里,可以通过这个键很方便的把所有的点赞数据都取出。这个键里面的数据还可以存成键值对的形式,方便存入点赞人、被点赞人和点赞状态。

设点赞人的 id 为 likedPostId,被点赞人

Java实现高性能功能,通常需要借助缓存系统来提升性能和并发处理能力。以下是实现高性能功能的关键思路和步骤: ### 缓存设计Redis使用 为了保证高并发下的性能,应优先使用内存数据库如 **Redis** 来存储状态以及相关的计数信息。通过将操作集中于 Redis 中,可以避免频繁访问关系型数据库,从而降低对数据库的压力。 - 每次用户对内容(例如文章或帖子)进行时,将记录保存到 Redis 中,键值格式为 `likedUserId::likedPostId`,其中 `likedUserId` 是被用户的 ID,而 `likedPostId` 是被内容的 ID。对应的值可以是 1 表示,0 表示取消[^2]。 - 同时维护一个额外的缓存条目用于记录每个用户的总数。例如,使用 `MAP_KEY_USER_LIKED_COUNT` 这样的键名来表示某个用户被的总次数,并在每次或取消时更新该计数[^3]。 ### 逻辑实现 对于和取消的操作,可以通过以下方式实现: ```java public interface RedisService { /** * 。状态为1 * @param likedUserId 被的用户ID * @param likedPostId 被的内容ID */ void saveLiked2Redis(String likedUserId, String likedPostId); /** * 取消。将状态改变为0 * @param likedUserId 被的用户ID * @param likedPostId 被的内容ID */ void unlikeFromRedis(String likedUserId, String likedPostId); /** * 该用户的数加1 * @param likedUserId 被的用户ID */ void incrementLikedCount(String likedUserId); /** * 该用户的数减1 * @param likedUserId 被的用户ID */ void decrementLikedCount(String likedUserId); } ``` 上述代码展示了如何定义 Redis 操作接口,具体实现可基于 Spring Data Redis 或其他 Redis 客户端库完成[^4]。 ### 数据持久化与一致性保障 虽然 Redis 提供了快速的读写速度,但为了防止数据丢失,还需要定期将 Redis 中的数据同步到持久化数据库中。可以采用定时任务的方式,例如每小时一次将 Redis 中的数据批量写入 MySQL 或 PostgreSQL 等关系型数据库中[^5]。 此外,双写一致性也是需要注意的问题。一种常见的解决方案是在更新 Redis 的同时发送消息至消息队列(如 Kafka 或 RocketMQ),由消费者异步更新数据库中的记录以保持最终一致性。 ### 性能优化建议 - **锁机制**:尽管直接使用锁可能会对系统并发性能产生一定影响,但在某些关键操作上仍需谨慎使用分布式锁(如 Redlock 算法)来确保数据一致性。 - **分片策略**:当业务规模扩大后,可以通过对 Redis 实施分片策略进一步提高系统的扩展性和可用性。 - **缓存穿透/击穿/雪崩防护**:针对这些常见问题采取相应的措施,比如设置空值缓存、添加随机过期时间等方法保护后端数据库不受冲击。 通过以上方法结合实际需求调整参数和技术选型,可以在 Java 应用程序中构建出既高效又稳定的功能模块
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猿码天地

相互学习,谢谢您的打赏。

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

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

打赏作者

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

抵扣说明:

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

余额充值