db::query()仅用于select类语句,返回解析后的关联数组结果集并支持参数绑定防注入;db::execute()专用于insert/update/delete等写操作,返回影响行数且不解析结果。

Db::query() 适合查数据,返回结果集
查出来的数据要遍历、分页或转数组,就用 Db::query()。它会解析 SQL,把结果自动映射成 PHP 数组(关联键是字段名),也支持参数绑定防注入。
常见错误是拿它去执行 INSERT、UPDATE,结果没报错但返回空数组,误以为成功了——其实它不关心影响行数,只管“有没有结果集”。
- 只用于
SELECT类语句,比如Db::query("SELECT * FROM user WHERE id = ?", [$id]) - 参数必须用问号占位,不能拼字符串,否则失去防注入能力
- 如果 SQL 有语法错误,会抛出
think\db\exception\DataNotFoundException异常,不是静默失败 - 不走模型事件(如
afterSelect),纯原生通道
Db::execute() 专干增删改,返回影响行数
写操作必须用 Db::execute()。它不解析结果,只返回 int 类型的受影响行数,0 表示没改到任何记录,-1 才是执行失败(比如语法错或权限不足)。
容易踩的坑是看到返回 0 就认定“SQL 没运行”,其实可能是 WHERE 条件没匹配上——这是业务逻辑问题,不是执行异常。
- 适用于
INSERT、UPDATE、DELETE、REPLACE等无结果集语句 - 同样支持问号绑定:
Db::execute("UPDATE user SET name = ? WHERE id = ?", [$name, $id]) - 不返回自增 ID,想拿刚插入的 ID 得额外调
Db::getLastInsID() - 事务中它和
query()共享同一个连接,不会意外提交
为什么不用 Db::table()->where()->update()?
当你需要复杂 SQL:比如多表 JOIN 更新、子查询条件、UNION 查询、或数据库特有函数(JSON_CONTAINS、ST_Distance),ORM 方法根本写不出来,硬套只会报错或生成错误 SQL。
这时候原生就是唯一选择。别为了“看起来优雅”硬拆成多个 ORM 链式调用,性能差还难调试。
- MySQL 的
INSERT ... ON DUPLICATE KEY UPDATE,ORM 不直接支持 - PostgreSQL 的
RETURNING子句,得靠query()才能拿到返回值 - 带变量的存储过程调用,例如
CALL proc_user_stats(?, ?) - 某些老版本 ThinkPHP 对 JSON 字段操作不稳定,原生更可控
事务里混用 query 和 execute 要注意什么
它们在同一个事务内是安全的,但要注意:如果先 execute() 插入一条记录,再 query() 查它,查不到是因为没提交——但这是预期行为,不是 bug。
真正容易被忽略的是连接复用带来的隐式行为:比如你手动用 PDO 开了新连接,或用了 Db::connect() 切库,那 query() 和 execute() 可能不在同一事务里。
- 确保所有操作都走同一个
Db实例(默认全局实例即可) - 不要在事务块里调
Db::close()或切换配置 - 批量操作时,
execute()单条执行比拼大 SQL 更稳,尤其涉及长文本或二进制 - 日志里看 SQL 执行顺序,比想象中更容易乱——建议开启
db_debug配置
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











