如何通过PHP+MySQL+Ajax实现单ID每日点赞更新次数上限控制
单条目每日点赞上限实现方案
这个需求完全可以基于你现有技术栈实现,不需要额外引入其他服务,核心是把单条目日维度的投票计数存在服务端,在投票逻辑里加一层原子校验即可,具体实现步骤如下:
1. 新增日投票计数表
你现有的表只存了条目的总点赞数,需要新增一张专门存每日投票计数的表,用来记录每个投票条目每天累计获得的票数,建表SQL如下:
CREATE TABLE `vote_daily_limit` ( `item_id` int UNSIGNED NOT NULL COMMENT '对应投票条目的ID', `vote_date` date NOT NULL COMMENT '计数归属日期(不带时分秒)', `daily_vote_count` int UNSIGNED NOT NULL DEFAULT '0' COMMENT '当日已累计投票数', PRIMARY KEY (`item_id`,`vote_date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
把item_id和vote_date设为联合主键,一是查询效率高,二是可以配合数据库行锁避免并发超量。
2. 改造后端投票接口逻辑
你原来的逻辑是收到Ajax请求后直接给对应条目的点赞数+1,现在要在更新前加日上限校验,注意必须用数据库事务+行锁保证操作原子性,不然高并发下会出现计数超过上限的问题。
核心逻辑流程:
- 收到前端传来的投票条目ID,以服务器当前日期为准(不要取前端传的日期,容易被篡改),用PHP的
date('Y-m-d')获取当日日期字符串。 - 开启数据库事务,先查询当前条目在当日的计数记录,查询时加
FOR UPDATE行锁,避免其他并发请求同时读取到旧的计数值。 - 如果当日没有对应计数记录,就初始化一条计数为0的记录。
- 判断当前计数是否已经达到你设置的上限(比如10次),如果已达上限直接回滚事务,给前端返回「今日投票次数已达上限」的错误响应。
- 如果没到上限,同步执行两个更新操作:一是把当日计数+1,二是把原条目表的总点赞数+1,之后提交事务,返回投票成功的响应。
PHP核心实现代码参考(基于PDO连接):
<?php // 提前完成数据库连接、获取前端传入的$itemId,设置每日单条目投票上限 $dailyMaxVote = 10; $today = date('Y-m-d'); try { $pdo->beginTransaction(); // 查询并锁定当日计数记录 $stmt = $pdo->prepare("SELECT daily_vote_count FROM vote_daily_limit WHERE item_id = ? AND vote_date = ? FOR UPDATE"); $stmt->execute([$itemId, $today]); $record = $stmt->fetch(PDO::FETCH_ASSOC); if (!$record) { // 当日无记录,初始化 $insertStmt = $pdo->prepare("INSERT INTO vote_daily_limit (item_id, vote_date, daily_vote_count) VALUES (?, ?, 0)"); $insertStmt->execute([$itemId, $today]); $currentCount = 0; } else { $currentCount = $record['daily_vote_count']; } // 校验是否达上限 if ($currentCount >= $dailyMaxVote) { $pdo->rollBack(); echo json_encode([ 'code' => 403, 'msg' => '该内容今日投票次数已达上限,请次日再试' ]); exit; } // 更新计数和总点赞数 $updateDaily = $pdo->prepare("UPDATE vote_daily_limit SET daily_vote_count = daily_vote_count + 1 WHERE item_id = ? AND vote_date = ?"); $updateDaily->execute([$itemId, $today]); $updateTotal = $pdo->prepare("UPDATE vote_items SET like_count = like_count + 1 WHERE id = ?"); $updateTotal->execute([$itemId]); $pdo->commit(); // 返回最新点赞数供前端更新 $newLikeCount = $pdo->query("SELECT like_count FROM vote_items WHERE id = {$itemId}")->fetchColumn(); echo json_encode([ 'code' => 0, 'msg' => '投票成功', 'data' => ['like_count' => $newLikeCount] ]); } catch (Exception $e) { $pdo->rollBack(); echo json_encode([ 'code' => 500, 'msg' => '系统错误,请稍后重试' ]); }
3. 前端Ajax逻辑适配
原有投票成功的逻辑保留,新增对返回状态码的判断:如果收到code=403的响应,直接弹出后端返回的提示即可,不要更新页面上的点赞数字。
注意事项
- 不要用Cookie、localStorage这类前端存储做计数限制,用户清缓存、换设备就能轻易绕过,所有计数逻辑必须落在服务端。
- 不需要单独写定时任务每日重置计数:因为计数是和日期绑定的,跨天后查询时会自动匹配新日期的记录,从0开始计数,没有额外维护成本。
- 如果后续需要加「单个用户每日只能给同一条目投1票」的规则,只需要在
vote_daily_limit表新增user_id字段,把联合主键改成(item_id, user_id, vote_date),逻辑和上述流程完全一致。
内容的提问来源于stack exchange,提问作者Justin van der Kwaak
相关产品推荐
相关产品推荐

