点赞功能作为社交、电商、内容平台等场景的核心交互模块,其实现需兼顾数据一致性、性能与并发安全性,本文将从基础设计到技术实现,详细拆解Java环境下的点赞功能开发逻辑,涵盖数据库设计、缓存策略、业务逻辑优化等关键环节。

基础需求与业务场景
点赞功能的核心需求包括:用户对目标对象(如文章、评论、商品)进行点赞/取消点赞操作,实时展示点赞数量,并支持查询用户点赞状态,常见业务场景中,需区分“普通点赞”与“点赞+踩”两种模式,本文以“普通点赞”为例展开,后者可扩展为双字段存储。
关键业务规则包括:
- 唯一性约束:同一用户对同一目标只能点赞一次,取消后可再次点赞;
- 实时性:点赞数量需即时更新,用户操作后能快速反馈;
- 数据一致性:缓存与数据库数据需同步,避免脏读或漏写。
数据库与缓存设计
数据库设计
点赞数据需持久化存储,核心表结构设计如下(以MySQL为例):
CREATE TABLE `user_like` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) NOT NULL COMMENT '用户ID', `target_id` bigint(20) NOT NULL COMMENT '目标对象ID(如文章ID)', `target_type` tinyint(4) NOT NULL COMMENT '目标类型(1:文章, 2:评论)', `like_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '点赞状态(1:点赞,0:取消)', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_user_target` (`user_id`, `target_id`, `target_type`) COMMENT '用户-目标唯一约束' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
设计要点:
- 联合唯一索引确保用户对同一目标只能有一条记录,避免重复点赞;
target_type字段支持多类型目标扩展,如文章、评论、商品等;like_status字段标识点赞状态,支持取消操作(逻辑删除)。
缓存设计
点赞操作高频读写,需引入缓存(如Redis)提升性能,缓存设计需满足:
- 点赞状态缓存:使用Hash结构存储用户对目标的点赞状态,Key格式为
like_status:{target_type}:{target_id},Field为user_id,Value为1(点赞)或0(取消); - 点赞数量缓存:使用String结构存储目标点赞数,Key格式为
like_count:{target_type}:{target_id},Value为数量值,初始为0。
缓存优势:减少数据库访问压力,响应速度提升至毫秒级;支持原子操作,避免并发问题。

核心业务逻辑实现
点赞/取消点赞流程
以“点赞”操作为例,核心逻辑如下(伪代码):
public void like(Long userId, Long targetId, Integer targetType) {
// 1. 检查缓存中的点赞状态
String statusKey = "like_status:" + targetType + ":" + targetId;
String countKey = "like_count:" + targetType + ":" + targetId;
// 2. 使用Redis原子操作(Lua脚本保证原子性)
String luaScript =
"local status = redis.call('HGET', KEYS[1], ARGV[1]) " +
"if status == 1 then " +
" return 0 " + // 已点赞,不做操作
"else " +
" redis.call('HSET', KEYS[1], ARGV[1], 1) " +
" redis.call('INCR', KEYS[2]) " +
" return 1 " + // 点赞成功
"end";
// 3. 执行Lua脚本,更新缓存
Long result = redisTemplate.execute(
new DefaultRedisScript<>(luaScript, Long.class),
Arrays.asList(statusKey, countKey),
userId.toString()
);
// 4. 若缓存操作成功,异步更新数据库
if (result == 1) {
asyncUpdateDatabase(userId, targetId, targetType, 1);
}
}
关键点:
- 使用Redis Lua脚本保证“检查-设置”操作的原子性,避免并发竞态;
- 缓存优先策略,先更新缓存再异步落库,提升响应速度;
- 取消点赞逻辑类似,将
HSET改为HDEL,INCR改为DECR。
查询点赞状态与数量
- 查询用户点赞状态:直接从Redis Hash中获取,若缓存未命中则查询数据库并回填缓存;
- 查询点赞数量:优先从Redis String获取,若缓存未命中则查询数据库并初始化缓存。
接口与交互设计
对外提供RESTful API,核心接口如下:
- 点赞/取消点赞:
POST /api/like,参数:userId(用户ID)、targetId(目标ID)、targetType(目标类型)、action(like/unlike); - 查询点赞状态:
GET /api/like/status?userId={userId}&targetIds={ids}&targetType={type},返回Map<targetId, Boolean>; - 查询点赞数量:
GET /api/like/count?targetIds={ids}&targetType={type},返回Map<targetId, Integer>。
接口规范:统一返回格式(如{code: 200, data: {...}}),参数校验(非空、类型校验),异常处理(如重复点赞、目标不存在)。
性能与并发优化
并发处理
- 分布式锁:在分布式环境下,使用Redis分布式锁(如Redission)控制并发点赞,避免同一用户短时间内重复操作;
- 限流机制:基于Redis滑动窗口算法限制用户点赞频率(如每分钟最多10次),防止恶意刷赞。
数据一致性
- 缓存与数据库同步:采用“先更新缓存,再异步更新数据库”策略,通过消息队列(如RabbitMQ)异步落库,避免数据库压力过大;
- 缓存重建:当数据库更新失败时,通过定时任务定期校验缓存与数据库一致性,修复异常数据。
批量查询优化
对于批量查询点赞状态(如获取某篇文章下100个用户的点赞情况),使用Redis HMGET命令一次性获取多个Field的值,减少网络IO次数。
扩展性与场景适配
多类型目标支持
通过target_type字段区分不同目标类型,如文章(1)、评论(2)、商品(3),无需为每种类型建表,提升扩展性。

分库分表
当数据量过大(如日点赞千万级),可按target_id或target_type进行分表,分散数据库压力。
点赞日志记录
单独建表存储点赞操作日志(含用户ID、目标ID、操作时间、IP等),用于用户行为分析或审计。
Java点赞功能的实现需从数据层、缓存层、业务层协同设计:数据库保证持久化与一致性,缓存提升性能,业务逻辑处理核心规则与并发场景,实际开发中,需根据业务规模选择合适的技术方案(如是否引入分布式锁、消息队列),并通过监控(如Prometheus)实时跟踪点赞系统的性能指标,确保稳定运行。















