点赞功能是内容类、社交类应用中非常常见的交互功能,使用mysql实现点赞功能时,核心是先设计合理的点赞数据表,再基于表结构实现对应的业务逻辑。合理的表设计能避免数据冗余,提升查询效率,减少后续维护成本。

点赞数据表设计
点赞数据表需要记录用户的点赞行为,核心要关联用户和目标内容,同时避免重复点赞。推荐设计如下表结构:
CREATE TABLE `user_like` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_id` bigint(20) NOT NULL COMMENT '点赞用户ID', `target_id` bigint(20) NOT NULL COMMENT '被点赞目标ID,比如文章ID、评论ID', `target_type` tinyint(4) NOT NULL COMMENT '目标类型,1文章 2评论 3动态,用于区分不同点赞对象', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '点赞状态,1点赞 0取消点赞', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_user_target` (`user_id`,`target_id`,`target_type`), KEY `idx_target` (`target_id`,`target_type`,`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户点赞记录表';
表设计的核心要点:
- 使用
user_id、target_id、target_type三个字段建立唯一索引,避免同一用户对同一目标重复点赞,同时支持取消点赞后再次点赞的场景。 - 增加
status字段而不是直接删除记录,方便后续统计用户的点赞历史,也避免频繁删除数据导致表碎片。 - 建立
target_id、target_type、status的联合索引,提升查询某目标点赞总数的效率。
点赞核心业务逻辑实现
用户点赞操作
用户点击点赞时,需要先判断是否已经点赞过,再执行对应操作。可以使用以下SQL实现:
INSERT INTO user_like (user_id, target_id, target_type, status) VALUES (1001, 2001, 1, 1) ON DUPLICATE KEY UPDATE status = IF(status = 1, 1, 1), update_time = CURRENT_TIMESTAMP;
这段SQL的逻辑是:如果用户没有点赞过该目标,就插入一条点赞记录;如果已经存在记录,就更新状态为1(点赞),同时更新修改时间。因为唯一索引的存在,不会插入重复记录。
用户取消点赞操作
用户取消点赞时,不需要删除记录,只需要更新status字段为0即可:
UPDATE user_like SET status = 0, update_time = CURRENT_TIMESTAMP WHERE user_id = 1001 AND target_id = 2001 AND target_type = 1;
查询用户是否点赞某目标
判断用户是否对某个目标点过赞,只需要查询对应记录的status即可:
SELECT status FROM user_like WHERE user_id = 1001 AND target_id = 2001 AND target_type = 1 LIMIT 1;
如果查询到结果且status为1,说明用户当前处于点赞状态;如果status为0或者没有查询到记录,说明用户没有点赞。
统计某目标的点赞总数
统计某篇文章、某条评论的点赞总数,只需要查询对应目标下status为1的记录数:
SELECT COUNT(*) AS like_count FROM user_like WHERE target_id = 2001 AND target_type = 1 AND status = 1;
业务层代码示例
以Java为例,实现点赞功能的业务层逻辑如下:
public class LikeService {
// 点赞操作
public boolean doLike(Long userId, Long targetId, Integer targetType) {
// 执行点赞SQL,返回影响行数
int rows = likeMapper.insertOrUpdateLike(userId, targetId, targetType);
return rows > 0;
}
// 取消点赞操作
public boolean cancelLike(Long userId, Long targetId, Integer targetType) {
int rows = likeMapper.updateLikeStatus(userId, targetId, targetType, 0);
return rows > 0;
}
// 查询用户点赞状态
public boolean isLiked(Long userId, Long targetId, Integer targetType) {
Integer status = likeMapper.selectLikeStatus(userId, targetId, targetType);
return status != null && status == 1;
}
// 查询目标点赞数
public Integer getLikeCount(Long targetId, Integer targetType) {
return likeMapper.selectLikeCount(targetId, targetType);
}
}
注意事项
- 如果点赞量非常大,单表数据增长过快,可以考虑按
target_type或者时间进行分表,提升查询效率。 - 高并发场景下,点赞操作可以加分布式锁,避免同一用户短时间内重复提交点赞请求导致数据异常。
- 如果不需要保留用户的点赞历史,也可以直接删除点赞记录,但建议保留
status字段的设计,方便后续扩展统计功能。