codeigniter中判断更新是否成功不能仅依赖affected_rows(),因其返回实际修改行数而非匹配行数;应结合select预查、启用client_found_rows模式或封装带matched/changing语义的方法来准确区分“未匹配”“无需更新”和“更新失败”。

CodeIgniter 中执行更新操作后,判断是否成功不能只看 affected_rows() 是否大于 0,尤其在 WHERE 条件匹配但新旧值完全相同时,MySQL 可能返回 0 行受影响,而实际 SQL 执行并无错误。正确方式需结合数据库驱动行为与业务逻辑综合判断。
理解 affected_rows() 的真实含义
affected_rows() 返回的是被修改(值真正发生变化)的行数,不是被匹配的行数。例如:
- 执行
UPDATE user SET status=1 WHERE id=100,但该用户当前 status 已是 1 → 返回 0 - 执行同一条语句,但当前 status 是 0 → 返回 1
- WHERE 条件没匹配到任何记录 → 也返回 0
仅靠 0/非0 无法区分「更新未生效」和「数据本来就没变」两种情况。
用 select + update 组合确认前提状态
若业务上必须知道“是否有数据被实际修改”,推荐先查再更:
- 用
$this->db->select()->where()->get()获取原始记录 - 比对关键字段是否已符合目标值
- 仅当存在差异时才执行 update,并用
affected_rows()验证执行结果
这样既能避免无意义更新,又能明确知道是「没匹配到」还是「无需更新」。
启用 MySQL 的 CLIENT_FOUND_ROWS 模式(可选)
部分场景下可让 MySQL 返回「匹配行数」而非「变更行数」。CodeIgniter 3 默认不启用,需手动配置:
- 在数据库配置数组中添加:
'mysqli' => [ 'client_flags' => MYSQLI_CLIENT_FOUND_ROWS ] - 注意:此设置影响所有查询,且仅对 MySQLi 有效,不适用于 PDO
- 启用后
affected_rows()在 WHERE 匹配但值未变时返回 1(匹配数),更接近直觉预期
统一封装更新方法提升可靠性
建议在模型中封装带语义的更新方法,例如:
public function update_with_result($table, $data, $where) {
$this->db->where($where);
$this->db->update($table, $data);
$affected = $this->db->affected_rows();
return [
'success' => $affected !== false,
'matched' => $this->db->count_all_results($table, FALSE), // 需提前重置 WHERE
'changed' => $affected > 0
];
}
返回结构化结果,便于控制器按需处理「失败」「未匹配」「已更新」等不同分支。











