db类操作需注意:find()返回单条(数组/null),select()返回数据集对象;save()仅模型可用,db需用insert/update;推荐name()自动处理前缀;原生sql用query()/execute(),链式操作须在find/select前完成。

直接用 Db 类做增删改查,不写 SQL 也能跑通,但容易在 find 和 select 返回值类型、空结果处理、主键识别逻辑上出错——尤其当你混用 save 和 insert 时。
find() 和 select() 的返回值差异必须分清
find() 返回单条记录(数组或 null),select() 返回数据集对象(可调用 toArray() 转数组,但默认不是数组)。很多人直接 foreach($res) 却没检查 $res 是不是对象,结果报错。
-
find()查不到数据时返回null,想返回空数组用findOrEmpty() -
select()查不到时返回空数据集对象(count($res) === 0),不是空数组;要转数组必须显式调用toArray() - 想查不到就抛异常?用
findOrFail()或selectOrFail(),别自己写if (!$res) throw new Exception(...) -
where条件缺失时,find()会返回表第一条数据(不加limit 1),而select()默认查全表——这点常被忽略
save() 不是 insert(),主键字段决定行为
save() 是模型级方法,它根据数据中是否含主键值(如 id)自动判断走新增还是更新。但用 Db::table()->save() 会报错:这个方法只在模型实例上可用,Db 查询器没有 save()。
- 正确姿势:用
Db::table('user')->insert($data)新增,Db::table('user')->where('id', 1)->update($data)更新 - 若要用
save(),必须基于模型,比如User::create($data)(新增)或User::find(1)->save($data)(更新) -
insert()成功返回插入行数(通常是1),update()返回影响行数,别拿它当布尔值判断成败 - 批量插入用
insertAll(),别循环调insert(),性能差且事务难控制
用 name() 还是 table()?前缀配置决定实际行为
Db::name('user') 会自动拼上前缀(如 think_),Db::table('user') 则按字面名查表。如果数据库表没加前缀,两者效果一样;但一旦配置了 'prefix' => 'think_',table('user') 就会去查 user 表(不存在),而 name('user') 查的是 think_user。
- 推荐统一用
name(),和模型层命名习惯一致,也避免手动拼接前缀出错 -
name()只能用于当前连接的默认前缀配置,跨库或动态前缀场景仍得用table()+ 完整表名 - 查不到数据时,先用
Db::getLastSql()打印真实 SQL,确认表名、字段、条件是否被正确解析
原生 SQL 执行必须用 query()/execute(),不能混进链式查询
Db::query() 专用于 SELECT,Db::execute() 用于 INSERT/UPDATE/DELETE。它们不支持链式调用,参数必须是完整 SQL 字符串 + 绑定数组。有人试图写 Db::table('user')->query($sql),这会报错。
- 需要复杂 JOIN 或函数计算时,优先用原生 SQL,别硬套链式查询
- 参数绑定用
:占位符(如:id),不要拼字符串,防注入 - 执行后想取自增 ID?
insertGetId()是唯一可靠方式,execute()返回的是影响行数,不是 ID - 事务中混合使用原生 SQL 和链式操作时,确保都在同一连接内,否则可能漏提交
最易被绕开的一点:所有链式操作(where、order、limit)必须在 find() 或 select() 前完成,调完之后再链式是无效的——TP 不会缓存中间状态,也不会报错,只会静默忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











