PDOStatement::rowCount()单次调用先返回行数后返回0的问题
问题分析与解决方案
核心问题拆解
无效的
lastInsertId()调用
你在UPDATE成功后写了$this->id = $pdo->lastInsertId();,但这个方法只用来获取INSERT操作生成的自增ID,UPDATE根本不会产生新的自增ID,这行代码完全没用,还可能干扰你对逻辑的判断。rowCount()两次输出的原因
你dump时看到1和0,说明update()函数被执行了两次:- 第一次执行时,数据确实有变化,rowCount返回1;
- 第二次执行时,提交的字段值和数据库里现有内容完全一致,哪怕WHERE条件匹配,MySQL也不会标记为“修改行”,此时rowCount返回0(哪怕你开了
MYSQL_ATTR_FOUND_ROWS,这个参数只保证返回匹配行数而非修改行数,但没有字段变化的话还是会返回0)。
具体修复步骤
1. 删掉无效代码
直接移除$this->id = $pdo->lastInsertId();这一行,你的$this->id已经是WHERE条件里的主键值,不需要重新赋值。
2. 排查函数重复调用
检查调用update()的地方,大概率是重复触发了执行:
- 在
update()开头加一行日志:error_log("update触发,ID: " . $this->id);,看日志里是否有两次相同ID的记录; - 检查前端按钮是否绑定了多次点击事件,或者表单是否被重复提交(比如AJAX请求没做防抖)。
3. 可选:调整更新判断逻辑
如果希望只要WHERE条件匹配(哪怕字段没变化)就返回true,可以改成先查是否存在对应行:
// 执行UPDATE $pdoStatement->execute([...]); // 检查目标行是否存在 $checkStmt = $pdo->prepare("SELECT 1 FROM album WHERE id = :id"); $checkStmt->execute([':id' => $this->id]); return $checkStmt->fetch() !== false;
不过这种方式会多一次查询,按需使用即可。
4. 验证PDO参数是否生效
虽然你设置了PDO::MYSQL_ATTR_FOUND_ROWS => true,可以加一行代码确认参数是否真的生效:
$pdo = Database::getPDO(); var_dump($pdo->getAttribute(PDO::MYSQL_ATTR_FOUND_ROWS));
如果输出bool(true)说明参数没问题,否则要检查Database类的getPDO方法是否正确返回了配置好的实例。
修正后的update函数示例
public function update() { $pdo = Database::getPDO(); $sql = "UPDATE `album` SET title = :title, description = :description, picture_preview = :picture_preview, album_visibility = :album_visibility, last_updated = :last_updated WHERE id = :id"; $pdoStatement = $pdo->prepare($sql); // 先判断SQL执行是否成功(无语法/权限错误) $executeSuccess = $pdoStatement->execute([ ':title' => $this->title, ':description' => $this->description, ':picture_preview' => $this->picture_preview, ':album_visibility' => $this->album_visibility, ':last_updated' => $this->last_updated, ':id' => $this->id ]); if (!$executeSuccess) { return false; } // 返回是否有行被修改 return $pdoStatement->rowCount() > 0; }
内容的提问来源于stack exchange,提问作者Manon-PM
相关产品推荐
相关产品推荐

