Db::name()复用单例连接池,db()默认每次新建连接;需显式传false参数才能复用db连接,否则循环中调用db()将频繁建连导致性能下降。

Db::name() 和 db() 助手函数,连接复用差别在哪
直接用 db('user') 做链式查询,性能容易掉坑里——它默认每次调用都新建数据库连接,不是单例。而 Db::name('user') 或 Db::table('user') 复用的是单例连接池里的 Connection 实例。
常见错误现象:foreach ($logs as $log) { db('log')->insert($log); } 等于每轮都连一次库,QPS 上不去还容易触发连接数限制。
- 想复用连接?必须显式传第三个参数
false:db('user', [], false) - 若需动态切换数据库配置(比如读写分离),
db()的第二个参数可传数组,但依然要加false才能避免重复连接 - 控制器中优先用
Db::name('user'),模型里用static::where(),避开db()的隐式开销
strict 模式为什么必须开,不开会怎样
默认情况下,where('non_exist_field', 1) 不会报错,只会让 SQL 查不到数据——因为字段名校验被关了。静默失败比报错更难排查。
开启方式有两种:
立即学习“PHP免费学习笔记(深入)”;
- 单次启用:
Db::name('user')->strict(true)->where('non_exist_field', 1)->select(),立刻抛出SQLSTATE[42S22]: Column not found - 全局启用:在数据库配置里加
'strict' => true
注意:strict 只校验主表字段,连表时关联表字段不检查;另外,buildSql() 不触发 strict 校验,得真执行才会暴露问题。
链式对象怎么安全复用,select() 之后还能不能链
select()、find()、delete() 这些终结方法一调就执行 SQL 并清空内部条件缓存,没法再链了。真正可复用的是构造过程中的 Query 对象本身。
- 正确做法:
$base = Db::name('user')->where('status', 1)->where('deleted_at', null),后续分支复用:$admins = $base->where('role', 'admin')->select() - 调试用:
$base->buildSql()返回带?占位符的字符串,不执行、不校验、不连库,适合日志或预览 - 别在
foreach里反复写Db::name('user')->where(),每次都会新建模型实例和查询器,复用$base更轻量
order() 传数组没生效,先查字段归属再定写法
order(['sort' => 'asc', 'id' => 'desc']) 看似没问题,但一旦用了 join 或视图,字段可能来自不同表,MySQL 会静默忽略——不报错也不排序。
- 查字段归属:
Db::getTableInfo('user', 'fields')确认sort确实在主表 - 连表时明确指定表别名:
order('u.sort asc, u.id desc')(假设主表 alias 为u) - MySQL 特有函数如
FIELD(status, 3, 2, 1)必须用字符串传,数组不支持
真正容易被忽略的是:db() 的连接行为、strict 的开关位置、以及 buildSql() 返回的占位符字符串——这些细节不验证,线上出问题时根本看不出哪儿错了。



















