Implementing a Like/Unlike Feature with Redis Caching and Periodic Persistence in Spring Cloud
This article details a complete backend solution for a high‑frequency like/unlike feature using Spring Cloud, Redis as a cache, MySQL for persistence, and Quartz to periodically transfer cached data to the database, covering installation, configuration, data modeling, service design, and scheduled tasks.
The article explains how to design and implement a like/unlike feature in a Spring Cloud microservice, using Redis as a cache and persisting data to a relational database every two hours.
Redis cache design and implementation : it shows Docker installation of Redis, Maven dependency for Spring Data Redis, enabling caching with @EnableCaching, and provides a RedisConfig class that creates RedisTemplate<String, Object> and StringRedisTemplate beans. The article describes Redis data structures (String, List, Set, Hash, Zset) and chooses Hash to store like data as a key likedUserId::likedPostId with value 1 (like) or 0 (unlike).
docker run -d -p 6379:6379 redis:4.0.8 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> public class RedisConfig {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// configuration omitted for brevity
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
// configuration omitted for brevity
}
}Database design : a MySQL table user_like with fields for the liked user ID, the liker ID, status, timestamps, and indexes is defined, together with the JPA entity UserLike and its repository.
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 '用户点赞表'; @Entity
@Data
public class UserLike {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String likedUserId;
private String likedPostId;
private Integer status = LikedStatusEnum.UNLIKE.getCode();
// constructors omitted
}Service layer : the RedisService interface defines methods for saving, un‑liking, deleting, incrementing counts, and retrieving data from Redis. Its implementation RedisServiceImpl uses RedisTemplate to operate on the hash maps defined by RedisKeyUtils. The LikedService interface provides CRUD operations and two methods transLikedFromRedis2DB() and transLikedCountFromRedis2DB() that move data from Redis to MySQL; the implementation LikedServiceImpl performs the actual transfer.
public interface RedisService {
void saveLiked2Redis(String likedUserId, String likedPostId);
void unlikeFromRedis(String likedUserId, String likedPostId);
void deleteLikedFromRedis(String likedUserId, String likedPostId);
void incrementLikedCount(String likedUserId);
void decrementLikedCount(String likedUserId);
List<UserLike> getLikedDataFromRedis();
List<LikedCountDTO> getLikedCountFromRedis();
} public class RedisServiceImpl implements RedisService {
@Autowired
RedisTemplate redisTemplate;
// method bodies omitted for brevity
} public interface LikedService {
UserLike save(UserLike userLike);
List<UserLike> saveAll(List<UserLike> list);
Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable);
Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable);
UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId);
void transLikedFromRedis2DB();
void transLikedCountFromRedis2DB();
} public class LikedServiceImpl implements LikedService {
@Autowired
UserLikeRepository likeRepository;
@Autowired
RedisService redisService;
// transactional methods omitted for brevity
}Scheduled persistence : Spring Quartz is used to run a job every two hours. QuartzConfig defines a JobDetail for LikeTask and a trigger with a two‑hour interval. LikeTask extends QuartzJobBean and calls the two transfer methods of LikedService.
@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();
}
} public class LikeTask extends QuartzJobBean {
@Autowired
LikedService likedService;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("LikeTask-------- {}", sdf.format(new Date()));
likedService.transLikedFromRedis2DB();
likedService.transLikedCountFromRedis2DB();
}
}In conclusion, the article provides a complete backend solution that combines Redis caching, MySQL persistence, Spring Data repositories, and Quartz scheduling to efficiently handle high‑frequency like operations while ensuring data durability.
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.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
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.
