Design and Implementation of a Like Feature Using Spring Cloud, Redis, and Quartz Scheduling
This article explains how to design a high‑frequency like/unlike feature by caching operations in Redis, persisting data to a relational database at regular intervals, and orchestrating the process with Spring Boot, Spring Cloud, and Quartz scheduled jobs, complete with code examples and schema design.
The article describes a complete solution for implementing a like/unlike functionality in a Spring Cloud application, focusing on performance optimization through Redis caching and periodic persistence to a relational database.
Redis Cache Design and Implementation
Installation and Running Redis
Docker command to start Redis: docker run -d -p 6379:6379 redis:4.0.8 If Redis is already installed, start it with:
redis-serverIntegrating Redis with Spring Boot
1. Add the dependency in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>2. Enable caching in the main application class:
@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. Create a Redis configuration class ( RedisConfig) that defines RedisTemplate and StringRedisTemplate beans with Jackson JSON serialization.
Redis Data Structures
Redis supports five data types: String, List, Set, Hash, and Zset. For the like feature, a Hash is chosen because it allows storing multiple fields (likedUserId, likedPostId, status) under a single key, making bulk retrieval easy.
Storing Like Data in Redis
The key format is likedUserId::likedPostId. The value is 1 for like and 0 for unlike. This enables quick lookup and aggregation by splitting the key on ::.
Database Design
The relational table user_like contains columns for the primary key, liked user ID, liked post ID, status, creation time, and update time. An example DDL:
create table `user_like`(
`id` int not null auto_increment,
`liked_user_id` varchar(32) not null comment '被点赞的用户id',
`liked_post_id` varchar(32) not null comment '点赞的用户id',
`status` tinyint(1) default '1' comment '点赞状态,0取消,1点赞',
`create_time` timestamp not null default current_timestamp comment '创建时间',
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间',
primary key(`id`),
INDEX `liked_user_id`(`liked_user_id`),
INDEX `liked_post_id`(`liked_post_id`)
) comment '用户点赞表';The corresponding JPA entity UserLike maps these fields and uses LikedStatusEnum for the status values.
Database Operations
Service interfaces RedisService and LikedService define methods for saving, updating, and querying like records. Implementations ( RedisServiceImpl and LikedServiceImpl) use RedisTemplate to read/write hash entries and convert them to domain objects.
Scheduled Persistence with Quartz
A Quartz job runs every two hours to transfer data from Redis to the database:
@Configuration
public class QuartzConfig {
private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";
@Bean
public JobDetail quartzDetail(){
return JobBuilder.newJob(LikeTask.class)
.withIdentity(LIKE_TASK_IDENTITY)
.storeDurably()
.build();
}
@Bean
public Trigger quartzTrigger(){
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInHours(2)
.repeatForever();
return TriggerBuilder.newTrigger()
.forJob(quartzDetail())
.withIdentity(LIKE_TASK_IDENTITY)
.withSchedule(scheduleBuilder)
.build();
}
}The job class LikeTask invokes likedService.transLikedFromRedis2DB() and likedService.transLikedCountFromRedis2DB() to synchronize both the like records and the like counts.
Conclusion
The solution demonstrates how to handle high‑frequency like operations efficiently by leveraging Redis as a write‑through cache, designing appropriate key/value structures, and using a Quartz‑driven batch job to persist data reliably, while providing full code snippets for each component.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
