ThinkPHP 的 saveAll 判断新增或更新只依据模型定义的 $pk 属性值是否存在于数据中且数据库存在对应记录,与字段名是否为 id 无关;必须显式声明 protected $pk = 'user_id';(大小写、下划线严格一致),否则默认按 id 查找,导致误插或更新失败;自增主键非 id 时还需设 protected $auto = true 并确保数据库字段为 AUTO_INCREMENT。

ThinkPHP 的 saveAll 判断新增还是更新,**只看模型里声明的主键字段值是否存在且数据库中已存在对应记录**,和字段名是不是 id 无关。关键不是“名字叫什么”,而是“模型认哪个字段是主键”。
必须显式设置 $pk 属性
如果数据库主键是 user_id、log_no 或其他非 id 字段,你必须在模型类中明确写:
-
protected $pk = 'user_id';(字符串,大小写、下划线必须完全一致) - 不能靠配置文件、运行时赋值或自动推断,TP6 不识别
$_pk或pk配置项 - 不设这行,模型默认用
id,所有saveAll、find、update都会按WHERE id = ?执行,结果查不到、全插新、更新失败
传入数据必须带对的主键字段
saveAll 是靠你传进去的数据里有没有这个 $pk 字段的值来判断逻辑的:
- 传
['user_id' => 1001, 'name' => '张三']→ 模型认user_id是主键 → 有值且库里存在 → 执行 UPDATE - 传
['id' => 1001, 'name' => '张三']→ 模型没设$pk = 'id'或设的是'user_id'→ 忽略id字段 → 当全新记录 INSERT - 传空
user_id(如null、0、'')→ 视为无主键值 → 强制 INSERT
验证主键是否生效的简单方法
别猜,直接测:
立即学习“PHP免费学习笔记(深入)”;
- 调用
UserModel::find(123),开启 SQL 日志,看生成的 WHERE 条件是WHERE user_id = 123还是WHERE id = 123 - 用一条含主键值的数据调
saveAll,观察执行的是INSERT还是UPDATE语句 - 检查模型实例:
echo (new UserModel())->getPk();应该输出你设的字段名,不是id
自增主键字段名改了,insertGetId() 还是 0?
因为 insertGetId() 默认从 id 字段读自增 ID。如果你的自增列是 log_id,除了设 $pk = 'log_id',还必须加:
-
protected $auto = true;(告诉 TP 这个字段是自增主键) - 确保数据库里该字段确实是
AUTO_INCREMENT(MySQL)或SERIAL(PostgreSQL) - 否则
saveAll插入后,模型对象里的$model->log_id仍是空或 0



















