ThinkPHP中检查数据是否存在需分场景:模型save前须手动where()+count()查重(更新时排除自身ID),验证器unique规则需显式传参排除ID,联合唯一必须用callback自定义校验并配合数据库联合索引,Excel导入应批量查重而非逐行查询。

ThinkPHP 里“检查数据是否存在”不是单一动作,而是分场景、分层级的逻辑组合:数据库查重是基础,验证器规则是门禁,联合索引是保险栓——三者缺一不可,且顺序不能乱。
模型 save() 前怎么查重避免重复插入
直接调用 save() 不会自动查重,哪怕字段加了 unique 规则。必须手动在写入前做一次 where() + count()。
- 新增场景:直接查
$this->where($data)->count(),返回 > 0 就说明已存在 - 更新场景:必须排除自身,加
->where('id', '', $this->id),否则自己总会“撞上自己” - 字段含 NULL 时要小心:
WHERE a = ? AND b = ?在 MySQL 中无法匹配(1, NULL),建议字段设为NOT NULL或提前用isset()/!is_null()过滤 - 别把查重逻辑塞进
beforeWrite就以为万事大吉——它不阻断执行,得配合return false或抛异常主动中断
验证器里用 unique 规则怎么排除当前 ID
unique 规则默认不区分新增/更新,必须显式传排除参数,否则编辑时总报“已存在”。
- TP6 写法:
['unique:users,email,' . $id . ',id'],其中第 3 个参数是值,第 4 个是字段名(可选,默认id) - TP8 推荐写法:
['unique' => 'users,email,id^' . $id],更直观;若主键是user_id,就得写成user_id^' . $user_id - 控制器中动态传参时,别拼
$_POST['id'],要用经过过滤的变量,比如$this->request->param('id/d') - 验证器类里拿不到上下文 ID?那就别硬塞进 rule 属性,改用闭包:
'email' => ['unique' => function($val) use ($id) { return 'users,email,id^' . $id; }]
联合字段唯一性为什么不能只靠 unique 规则
unique 规则在 TP6/TP8 中**不原生支持多字段联合校验**。写成 unique:users,username,email 会报错或静默失效。
立即学习“PHP免费学习笔记(深入)”;
- 真正能用的只有单字段全局唯一,比如邮箱、手机号本身独立不能重复
- 像
user_id + sku_id这种组合,必须走自定义验证:Rule::callback()或手动where(['user_id'=>$u,'sku_id'=>$s])->count() - 数据库联合索引必须先建好:
ALTER TABLE order_items ADD UNIQUE KEY uk_user_sku (user_id, sku_id);,否则应用层再怎么查,高并发下照样插入重复 - 索引字段顺序要和查询条件一致:(user_id, sku_id) 能加速
WHERE user_id=? AND sku_id=?,但对WHERE sku_id=?无效
Excel 批量导入时怎么高效跳过重复记录
逐行查 find() 是性能黑洞,1000 行可能触发上千次查询。必须批量查、一次性比对。
- 先提取所有待导入的组合键,比如
$keys = array_column($rows, 'user_id', 'sku_id'); - 用
concat拼接后查库:Db::name('order_items')->where('concat(user_id,"_",sku_id)', 'in', $keys)->column('concat(user_id,"_",sku_id)'); - 用
array_diff_key()筛出新数据,再insertAll();别混着插,否则一条失败整批回滚 - 注意 Excel 导出的数字可能被读成字符串,
"123"和123在 MySQL 中不等价,入库前统一intval()或trim() - NULL 值在联合索引中不生效:(1, NULL) 和 (1, NULL) 被视为不同记录,导入前确保关键字段非空
最易被忽略的一点:验证器里的 unique 规则和数据库唯一索引是两套逻辑,前者只做前置拦截,后者才是最终防线。但如果没有索引,验证通过也拦不住并发写入;如果没写验证,索引冲突只会抛 Integrity constraint violation,前端根本没法提示具体哪条重复。



















