MySQLi多表查询与单条宠物数据重复更新问题求助
问题分析
你的问题根源很清晰:更新操作的逻辑被放在了遍历所有宠物的while循环内部。当你点击提交按钮后,页面重新加载时会先查询当前用户的所有宠物,然后每循环一只宠物就会检查一次$_GET参数。只要满足条件(比如buy=clean、资金足够),就会执行一次更新——你有多少只宠物,就会执行多少次更新,这就是指定宠物信息被重复修改的原因。
解决方案
我们需要把更新逻辑和宠物展示逻辑彻底分开:先处理提交的更新请求(只执行一次),再查询并展示所有宠物信息。这样不管用户有多少只宠物,更新操作只会触发一次。
具体调整思路:
- 先获取用户当前资金,用于后续的更新条件判断;
- 检查是否存在
$_GET['buy']和$_GET['identifier']参数,若存在则执行对应的更新操作(完全脱离宠物遍历循环); - 最后再查询所有宠物信息,循环展示每只宠物的内容和操作按钮。
修改后的完整代码
<?php // 先获取用户当前资金,用于后续条件判断 $statement = $mysqli->prepare("SELECT money FROM users WHERE fbid = ?"); $statement->bind_param("s", $_SESSION['FBID']); $statement->execute(); $statement->bind_result($money); $statement->fetch(); // 仅查询一行数据,无需while循环 $statement->close(); // 处理更新请求:放在宠物遍历循环外,确保只执行一次 if (isset($_GET['buy']) && isset($_GET['identifier'])) { $buyType = $_GET['buy']; $targetPet = $_GET['identifier']; if ($buyType === 'clean' && $money >= 5) { // 先检查目标宠物的当前清洁度是否符合更新条件 $checkStmt = $mysqli->prepare("SELECT clean FROM pets WHERE fbid = ? AND petname = ?"); $checkStmt->bind_param("ss", $_SESSION['FBID'], $targetPet); $checkStmt->execute(); $checkStmt->bind_result($currentClean); $checkStmt->fetch(); $checkStmt->close(); if ($currentClean <= 95) { // 更新宠物清洁度 $updatePetStmt = $mysqli->prepare("UPDATE pets SET `clean` = `clean` + 5 WHERE fbid = ? AND petname = ?"); $updatePetStmt->bind_param("ss", $_SESSION['FBID'], $targetPet); $updatePetStmt->execute(); $updatePetStmt->close(); // 扣除用户资金 $updateUserStmt = $mysqli->prepare("UPDATE users SET `money` = `money` - 5 WHERE fbid = ?"); $updateUserStmt->bind_param("s", $_SESSION['FBID']); $updateUserStmt->execute(); $updateUserStmt->close(); header("Location: /pets.php?success=clean"); exit; // 跳转后终止脚本,避免后续代码执行 } } elseif ($buyType === 'health' && $money >= 7) { // 先检查目标宠物的当前健康度是否符合更新条件 $checkStmt = $mysqli->prepare("SELECT health FROM pets WHERE fbid = ? AND petname = ?"); $checkStmt->bind_param("ss", $_SESSION['FBID'], $targetPet); $checkStmt->execute(); $checkStmt->bind_result($currentHealth); $checkStmt->fetch(); $checkStmt->close(); if ($currentHealth <= 90) { // 更新宠物健康度 $updatePetStmt = $mysqli->prepare("UPDATE pets SET `health` = `health` + 10 WHERE fbid = ? AND petname = ?"); $updatePetStmt->bind_param("ss", $_SESSION['FBID'], $targetPet); $updatePetStmt->execute(); $updatePetStmt->close(); // 扣除用户资金 $updateUserStmt = $mysqli->prepare("UPDATE users SET `money` = `money` - 7 WHERE fbid = ?"); $updateUserStmt->bind_param("s", $_SESSION['FBID']); $updateUserStmt->execute(); $updateUserStmt->close(); header("Location: /pets.php?success=health"); exit; } } } // 最后查询并展示所有宠物信息 if ($stmt = $mysqli->prepare("SELECT clean,health,petname FROM pets WHERE fbid = ?")) { $stmt->bind_param('s', $_SESSION['FBID']); $stmt->execute(); $stmt->store_result(); $num_of_rows = $stmt->num_rows; $stmt->bind_result($clean,$health,$petname); while ($stmt->fetch()) { echo "{$petname} welcomes you!<br>"; // 展示健康护理按钮(判断条件) if ($health <= 90 && $money >= 7) { echo "<form method='GET'> <input type='hidden' name='identifier' value='{$petname}'> <input type='hidden' name='buy' value='health'> <input type='submit' value='Healthcare (G$7)'> </form>"; } // 展示清洁按钮(判断条件) if ($clean <= 95 && $money >= 5) { echo "<form method='GET'> <input type='hidden' name='identifier' value='{$petname}'> <input type='hidden' name='buy' value='clean'> <input type='submit' value='Clean (G$5)'> </form>"; } } $stmt->free_result(); $stmt->close(); } ?>
关键优化点
- 更新逻辑独立:将更新操作从宠物遍历循环中抽离,确保提交请求后只执行一次更新;
- 前置属性检查:在更新前先查询目标宠物的当前属性值,避免出现清洁度/健康度超过100的不合理情况;
- 跳转后终止脚本:使用
exit确保跳转后脚本不再继续执行,避免不必要的代码运行; - 简化资金查询:因为
users表仅查询一行数据,直接用一次fetch()即可,无需多余的while循环。
内容的提问来源于stack exchange,提问作者krisz44g
相关产品推荐
相关产品推荐

