CI4 的 Model::update() 必须传主键 ID 且配置 $primaryKey,否则可能静默更新整表;需严格设置 $allowedFields 白名单,单选字段要校验合法性并类型转换;返回值为影响行数或 false,不可直接用 if 判断。

CI4 模型 update() 必须传主键 ID,否则更新整张表
CI4 的 Model::update() 方法默认按主键更新,不是按 where 条件。如果你没传 ID 或模型没配对 $primaryKey,它会静默失败或更新所有行——这是最常踩的坑。
常见错误现象:update() 执行后数据库没变化,或整张表字段全被设成同一个值;日志里看不到 SQL,也没有报错。
- 确保模型中定义了
protected $primaryKey = 'id';(字段名要和表一致) - 调用时必须传入 ID:例如
$model->update($id, $data),不能只传$data - 如果 ID 来自表单,务必用隐藏域传递,且在控制器里用
$this->request->getPost('id')取值,别漏校验是否为空 - 若想按其他字段更新(比如
where('status', 'pending')),就别用update(),改用 Query Builder 的$model->builder()->where(...)->update($data)
allowedFields 是安全开关,不配就 update() 直接返回 false
$allowedFields 不是可选配置,是强制白名单。哪怕只更新一个字段,只要字段名不在这个数组里,update() 就会静默拒绝,返回 false,且不抛异常。
使用场景:用户提交单选按钮值(如 anotasi),但模型没把该字段放进 $allowedFields,结果数据根本存不进库。
- 在模型类里明确定义:
protected $allowedFields = ['anotasi', 'updated_at']; - 字段名必须完全匹配数据库列名,区分大小写
- 不要试图用
*或动态生成,CI4 不支持通配符 - 开发阶段可临时设为
['*']用于调试,上线前必须删掉
单选按钮值提交后,控制器要先验证再传给模型
前端单选按钮(<input type="radio" name="anotasi" value="Positif">)提交的是字符串,但数据库字段可能是 ENUM、TINYINT 或 VARCHAR。类型不一致会导致更新失败或存入意外值。
容易忽略的点:用户可能不选任何选项,$this->request->getPost('anotasi') 会返回 null,直接传给模型可能触发空值插入或验证失败。
- 用
in_array()校验值是否合法:in_array($value, ['Positif', 'Negatif', 'Netral']) - 设置默认 fallback:
$anotasi = $this->request->getPost('anotasi') ?: 'Netral'; - 避免在控制器里拼 SQL 或手动构造数组,把清洗后的干净数据交给模型
- 若字段是整型(如 1/0),记得用
(int)转换,别依赖 MySQL 自动转换
update() 返回值不是布尔值,而是影响行数或 false
Model::update() 成功时返回受影响的行数(通常是 1),失败才返回 false。很多人用 if ($model->update(...)) 判断成功,结果 if(1) 为真,if(0) 也为假——但 0 表示“找到记录但没更新任何字段”,这其实算逻辑成功,只是值没变。
性能影响:每次 update() 都会触发 updated_at 时间戳更新(如果启用了),即使字段值没变,也会写一次磁盘。
- 判断是否真正更新了数据,应检查返回值是否
!== false,而不是是否为真 - 想区分“更新成功”和“无变更”,得自己比对旧值:
if ($model->find($id)['anotasi'] !== $newAnotasi) - 批量更新多个 ID 时,
update()不支持数组 ID,得用循环或 Query Builder 的whereIn()


















