高效用好ThinkPHP查询构造器的关键在于写得准、复用强、错得少:需理解链式返回值、区分Db与Model职责、手动控制条件分组;基础条件应复用变量,复杂逻辑用闭包或数组条件明确分组;避免混用Db和Model方法,批量操作优先用insertAll等内置方案。

高效用好ThinkPHP查询构造器,关键不在写得多,而在写得准、复用强、错得少。核心是理解链式返回值、区分Db和Model职责、控制条件分组逻辑。
链式操作别在中途执行,先攒着再用
每次调用 select() 或 find() 都会立刻查库。如果多个地方要用相似条件(比如都排除软删除、限定租户),反复写 User::where('deleted_at', null)->where('tenant_id', 1)->... 不仅冗余,还新建了多次查询对象。
- 把基础条件存成变量:
$base = User::where('deleted_at', null)->where('tenant_id', $tid); - 后续加条件再执行:
$list = $base->where('status', 1)->select();或$admin = $base->where('role', 'admin')->select(); - 想看生成的SQL调试?调
$base->buildSql(),它返回带占位符的原始语句,不执行也不绑定参数
where 和 whereOr 的括号必须手动管住
直接链式写 ->where('a', 1)->whereOr('b', 2) 看似简单,但框架自动加括号的逻辑容易偏离预期——尤其当条件变多时,OR 可能包住整个前面的 AND 块,导致结果错漏。
- 需要“(A AND B)OR(C AND D)”?用闭包明确分组:
->whereOr(function ($q) { $q->where('type', 'vip')->where('score', '>', 90); }) - 混合“且+或”时,优先用数组条件:
where([['name', 'like', '%x%'], ['or', [['mobile', 'like', '%y%'], ['email', 'like', '%z%']]]]) - 避免字符串拼接条件(如
"status=1 OR vip=1"),既不安全又绕过框架字段校验
Db 和 Model 别混着用,返回值类型要盯紧
Db::name() 是查询器,User::class 是模型。它们方法名相似,但行为和返回值差异明显,混用是 runtime 报错高发区。
立即学习“PHP免费学习笔记(深入)”;
-
find()返回数组或null;select()返回数据集对象(不是数组!foreach 前记得toArray()) -
save()只属于模型实例,Db::table()->save()必报错;新增用insert(),更新用update() - 表名统一用
name('user'),它自动拼前缀;table('user')是字面名,配了前缀却没生效,十有八九是这儿错了 - 查不到数据时,先打
Db::getLastSql(),确认生成的 SQL 表名、字段、WHERE 是否真如你所想
批量操作别手写循环,事务和性能一起保
单条 insert() 在循环里跑几十次,等于几十次数据库往返,还难套事务。框架提供了更稳更快的方案。
- 批量插入用
insertAll($dataList),一次请求完成,支持事务包裹 - 批量更新不用循环
update(),改用原生 SQL +execute()或结合when()+case构建条件更新 - 删数据慎用
delete()直删,优先考虑软删除(update(['deleted_at' => date('Y-m-d H:i:s')])),留痕可溯



















