ThinkPHP执行原生SQL核心是查用Db::query()、改用Db::execute();混用会导致静默错误,如query执行UPDATE返回空数组但数据已改,execute执行SELECT返回数字引发遍历报错。

ThinkPHP 执行原生 SQL,核心就两条路:查数据用 Db::query(),改数据用 Db::execute()。混用会出问题——比如用 query 执行 UPDATE,语句实际执行了,但返回空数组 [],容易误判为“没成功”;反过来用 execute 执行 SELECT,返回的是数字(如 0 或 1),当成数组遍历直接报错。
查数据:用 Db::query(),返回二维数组
只适用于 SELECT、SHOW、EXPLAIN、WITH 等能返回结果集的语句。返回值是标准二维数组,可直接 foreach 或传给模板。
- 问号占位符(简洁):
Db::query('SELECT * FROM user WHERE status = ? AND id > ?', [1, 100]); - 命名占位符(推荐,语义清晰):
Db::query('SELECT id,name FROM user WHERE role = :role', ['role' => 'admin']); - LIKE 模糊匹配:通配符必须包在绑定值里,例如
['%' . $kw . '%'],不能写成?% - 读写分离下默认走从库;如需主库查询,加第三个参数
true:Db::query($sql, $params, true)
改数据:用 Db::execute(),返回影响行数
专用于 INSERT、UPDATE、DELETE、TRUNCATE、REPLACE 等写操作。返回整数(成功为影响行数,失败为 false),不返回数据本身。
- 单条更新:
Db::execute('UPDATE user SET last_login = NOW() WHERE id = ?', [123]); - 批量插入(注意参数顺序一一对应):
Db::execute('INSERT INTO log (uid, action, ip) VALUES (?, ?, ?), (?, ?, ?)', [1,'login','192.168.1.1', 2,'logout','192.168.1.2']); - 获取刚插入的 ID 需额外调:
Db::getLastInsID(),execute本身不提供 - 误用
query执行DELETE是典型翻车点:语句执行了,但返回[],容易误判为“没删成”
安全绑定:值可用占位符,表名字段名必须白名单校验
占位符(? 或 :key)只防「值」注入,对表名、字段名、ORDER BY、GROUP BY 等动态部分完全无效。这些必须提前校验,严禁直拼。
- 错误示范:
ORDER BY ?→ 会被当字符串字面量,排序失效 - 正确做法:先白名单过滤再拼接,例如
$allowedSorts = ['id','name','create_time'];
if (!in_array($sortField, $allowedSorts)) { throw new \Exception('非法排序字段'); }
Db::query("SELECT * FROM user ORDER BY {$sortField} DESC"); - 表名占位
{:table}或__TABLE__仍是语法糖,仍需白名单校验:if (!in_array($table, ['user', 'order'])) { ... }
跨库和子查询要手写全 SQL
Db::query() 是唯一支持跨库 JOIN 的方式,但必须显式带上库名,例如:SELECT u.id FROM db1.user u JOIN db2.order o ON u.id = o.user_id。框架的 join() 方法会强制加当前库前缀,跨库必报错。
- 子查询不被自动解析,必须手写完整 SQL 字符串,例如:
SELECT * FROM (SELECT id, name FROM user WHERE status = 1) AS t - 临时表方案可用于复杂逻辑:
Db::query("CREATE TEMPORARY TABLE tmp_user AS SELECT id FROM db1.user"),再关联查询,记得清理:Db::query("DROP TEMPORARY TABLE IF EXISTS tmp_user") - MySQL 8.0+ 下若报错,检查 PDO 是否开启模拟预处理:
PDO::ATTR_EMULATE_PREPARES => true
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











