PHP项目中统计"协防补位成功次数"的实现方案
由于你没有提供具体的项目代码,我给出一个通用的设计思路和实现方案,你可以根据实际项目结构进行调整。

先明确业务概念
协防补位成功通常指:
- 玩家 A 的防守位置被攻击时,玩家 B 前往支援
- B 到达时该位置仍在战斗中
- 最终防守成功(未被攻破)
不同游戏定义不同,需要先确认清楚。
数据库设计
方案1:日志表 + 聚合统计(推荐)
-- 协防行为记录表 CREATE TABLE `assist_defense_log` ( `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `helper_id` INT UNSIGNED NOT NULL COMMENT '协防者UID', `target_id` INT UNSIGNED NOT NULL COMMENT '被协防者UID', `battle_id` BIGINT UNSIGNED NOT NULL COMMENT '战斗ID', `position_id` INT NOT NULL COMMENT '补位位置', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0进行中 1成功 2失败', `created_at` INT UNSIGNED NOT NULL, `finished_at` INT UNSIGNED DEFAULT 0, KEY `idx_helper_status` (`helper_id`, `status`), KEY `idx_battle` (`battle_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
方案2:计数器字段(查询快)
ALTER TABLE `user_stat` ADD COLUMN `assist_defense_success` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '协防补位成功次数', ADD COLUMN `assist_defense_total` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '协防补位总次数';
PHP 代码实现
记录协防行为(战斗开始时)
class AssistDefenseService
{
private PDO $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
/**
* 记录协防补位(战斗开始时调用)
*/
public function recordAssist(int $helperId, int $targetId, int $battleId, int $positionId): int
{
$sql = "INSERT INTO assist_defense_log
(helper_id, target_id, battle_id, position_id, status, created_at)
VALUES (:helper_id, :target_id, :battle_id, :position_id, 0, :now)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':helper_id' => $helperId,
':target_id' => $targetId,
':battle_id' => $battleId,
':position_id' => $positionId,
':now' => time(),
]);
return (int)$this->db->lastInsertId();
}
/**
* 战斗结束时更新结果(协防成功才累计)
*/
public function finishAssist(int $battleId, bool $defenseSuccess): void
{
$this->db->beginTransaction();
try {
// 找出这场战斗的所有协防记录
$stmt = $this->db->prepare(
"SELECT id, helper_id FROM assist_defense_log
WHERE battle_id = :bid AND status = 0 FOR UPDATE"
);
$stmt->execute([':bid' => $battleId]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($rows)) {
$this->db->commit();
return;
}
$newStatus = $defenseSuccess ? 1 : 2;
// 更新日志状态
$updateStmt = $this->db->prepare(
"UPDATE assist_defense_log
SET status = :status, finished_at = :now
WHERE id = :id"
);
// 成功则累加用户统计
$incStmt = $this->db->prepare(
"UPDATE user_stat
SET assist_defense_success = assist_defense_success + 1,
assist_defense_total = assist_defense_total + 1
WHERE uid = :uid"
);
$incTotalStmt = $this->db->prepare(
"UPDATE user_stat
SET assist_defense_total = assist_defense_total + 1
WHERE uid = :uid"
);
foreach ($rows as $row) {
$updateStmt->execute([
':status' => $newStatus,
':now' => time(),
':id' => $row['id'],
]);
if ($defenseSuccess) {
$incStmt->execute([':uid' => $row['helper_id']]);
} else {
$incTotalStmt->execute([':uid' => $row['helper_id']]);
}
}
$this->db->commit();
} catch (Throwable $e) {
$this->db->rollBack();
throw $e;
}
}
}
查询某玩家的协防补位成功次数
/**
* 从计数器读(推荐,需保证写入时同步)
*/
public function getAssistSuccessCount(int $uid): int
{
$stmt = $this->db->prepare(
"SELECT assist_defense_success FROM user_stat WHERE uid = :uid"
);
$stmt->execute([':uid' => $uid]);
return (int)($stmt->fetchColumn() ?: 0);
}
/**
* 从日志表实时聚合(数据量大时慢,适合对账)
*/
public function getAssistSuccessCountByLog(int $uid): int
{
$stmt = $this->db->prepare(
"SELECT COUNT(*) FROM assist_defense_log
WHERE helper_id = :uid AND status = 1"
);
$stmt->execute([':uid' => $uid]);
return (int)$stmt->fetchColumn();
}
进阶:Redis 缓存加速
如果是高并发游戏,用 Redis 做实时计数:
class AssistDefenseCounter
{
private Redis $redis;
private PDO $db;
public function __construct(Redis $redis, PDO $db)
{
$this->redis = $redis;
$this->db = $db;
}
public function incr(int $uid, int $delta = 1): void
{
$key = "assist:success:{$uid}";
$this->redis->incrBy($key, $delta);
// 加入待持久化队列
$this->redis->sAdd('assist:sync:pending', $uid);
}
public function get(int $uid): int
{
$key = "assist:success:{$uid}";
if ($this->redis->exists($key)) {
// 缓存没命中就回源
}
$val = $this->redis->get($key);
if ($val !== false) {
return (int)$val;
}
return $this->getAssistSuccessCount($uid);
}
/** 定时任务批量刷回 DB */
public function flushToDb(): void
{
$uids = $this->redis->sMembers('assist:sync:pending');
foreach ($uids as $uid) {
$val = (int)$this->redis->get("assist:success:{$uid}");
// 更新 MySQL...
$this->redis->sRem('assist:sync:pending', $uid);
}
}
}
需要你补充的信息
要给出贴合你项目的代码,请告诉我:
- 框架:Laravel / ThinkPHP / 原生 PHP / Hyperf / Swoole?
- 业务定义:怎么才算"协防补位成功"?(战斗胜利?补位到位?)
- 触发点:哪个接口/事件里触发(战斗结算、定时任务?)
- 表结构:现有的用户表、战斗表、日志表字段?
- 统计需求:是实时查、定时统计、还是活动期内累计?
把关键代码/表结构贴出来,我可以帮你直接改写成可落地的代码。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播