点赞功能是内容平台、社交应用中的基础交互功能,核心需求是记录用户对内容的点赞状态,支持点赞、取消点赞操作,同时能快速统计内容的总点赞数。借助mysql实现该功能,需要从表结构设计、核心逻辑编写、并发处理三个层面逐步推进。

一、数据库表结构设计
实现点赞功能需要两张核心表,分别是内容表和用户点赞记录表,具体设计如下:
1. 内容表(article)
内容表用于存储内容的基础信息,其中需要包含点赞数字段,避免每次统计点赞数都去查询点赞记录表,提升查询效率。
CREATE TABLE `article` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '内容ID', `title` varchar(255) NOT NULL COMMENT '内容标题', `content` text NOT NULL COMMENT '内容正文', `like_count` int(11) NOT NULL DEFAULT '0' COMMENT '总点赞数', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='内容表';
2. 用户点赞记录表(user_like)
该表用于记录每个用户对每个内容的点赞状态,通过联合唯一索引避免重复点赞,同时支持快速查询用户是否对某内容点过赞。
CREATE TABLE `user_like` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '记录ID', `user_id` int(11) NOT NULL COMMENT '用户ID', `article_id` int(11) NOT NULL COMMENT '内容ID', `status` tinyint(1) 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_article` (`user_id`,`article_id`) COMMENT '用户和内容联合唯一索引,避免重复记录' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户点赞记录表';
二、核心功能实现
1. 点赞操作
点赞操作需要同时处理点赞记录表和内容表的点赞数,为了保证数据一致性,需要使用事务。逻辑如下:先查询用户是否对该内容有过点赞记录,如果没有则插入记录,同时内容表点赞数加1;如果已有记录且状态是取消点赞,则更新记录状态为点赞,同时内容表点赞数加1。
-- 开启事务 START TRANSACTION; -- 查询用户是否对该内容有过点赞记录 SELECT `status` FROM `user_like` WHERE `user_id` = 1 AND `article_id` = 100 FOR UPDATE; -- 如果没有记录,插入点赞记录 INSERT INTO `user_like` (`user_id`, `article_id`, `status`) VALUES (1, 100, 1); -- 内容表点赞数加1 UPDATE `article` SET `like_count` = `like_count` + 1 WHERE `id` = 100; -- 提交事务 COMMIT;
如果查询到已有记录且status为0,只需要执行更新和加1操作即可:
START TRANSACTION; UPDATE `user_like` SET `status` = 1 WHERE `user_id` = 1 AND `article_id` = 100; UPDATE `article` SET `like_count` = `like_count` + 1 WHERE `id` = 100; COMMIT;
2. 取消点赞操作
取消点赞的逻辑和反向,需要更新点赞记录表的状态为0,同时内容表的点赞数减1,同样需要事务保证一致性。
START TRANSACTION; UPDATE `user_like` SET `status` = 0 WHERE `user_id` = 1 AND `article_id` = 100; UPDATE `article` SET `like_count` = `like_count` - 1 WHERE `id` = 100; COMMIT;
3. 查询用户点赞状态与内容点赞数
查询用户是否对某内容点过赞,直接查询点赞记录表即可:
SELECT `status` FROM `user_like` WHERE `user_id` = 1 AND `article_id` = 100;
查询某内容的总点赞数,直接查询内容表的like_count字段即可,不需要去点赞记录表统计,效率更高:
SELECT `like_count` FROM `article` WHERE `id` = 100;
三、并发场景处理
在高并发场景下,多个用户同时对同一内容点赞可能会出现数据不一致的问题,比如点赞数统计错误。上面的实现中已经使用了FOR UPDATE行锁,在查询用户点赞记录时对相关行加锁,避免并发插入重复记录。另外也可以在应用层做幂等处理,比如引入分布式锁,对同一个内容的点赞操作加锁,保证同一时间只有一个请求能处理该内容的点赞逻辑。
四、优化建议
- 如果点赞量非常大,用户点赞记录表可以做分表处理,比如按照用户ID或者内容ID取模分表,提升查询和写入效率。
- 内容表的点赞数可以定期从点赞记录表同步,避免极端情况下点赞数和实际记录不一致,比如事务执行到一半中断的情况,可以定时校验修正。
- 如果不需要保留用户的点赞历史,也可以简化表结构,只保留内容表的点赞数字段,点赞时直接加1,取消时减1,但这种方式无法支持查询用户的点赞状态,也不适合需要统计用户点赞列表的场景。