原生sql在thinkphp中必须严格区分db::query()与db::execute()——前者仅用于select/show/explain并返回二维数组,后者专用于insert/update/delete且返回影响行数;参数须用占位符绑定,动态部分需白名单校验,事务中执行原生sql须手动控制并避免非事务语句。

原生 SQL 在 ThinkPHP 里不是“能不能写”,而是“必须分清 query 还是 execute”——用错一个,轻则数据没变、重则查出空数组还误以为成功。
Db::query() 只能用于 SELECT/SHOW/EXPLAIN
它返回二维数组,适合后续 foreach 或模板 volist 渲染。一旦拿它执行 UPDATE 或 INSERT,语句其实跑了,但返回值是空数组,你接着 foreach 就直接报错。
- 正确:
Db::query("SELECT * FROM user WHERE status = ? AND name LIKE ?", [1, "%{$kw}%"]) - 错误:
Db::query("UPDATE user SET age = 25 WHERE id = 8")—— 不报错,但返回[],逻辑可能悄悄断裂 - 注意
LIKE的通配符要拼在 PHP 变量里,别塞进 SQL 字符串:["%{$kw}%"]✅,["%?%"]❌
Db::execute() 专管 INSERT/UPDATE/DELETE/REPLACE
它走的是 PDO 的 exec(),返回影响行数(int)或 false,不返回数据。这是写操作的唯一正途。
- 正确:
Db::execute("UPDATE user SET name = ? WHERE id = ?", ['张三', 8]) - 也支持命名占位符:
Db::execute("DELETE FROM log WHERE level = :level AND time > :start", ['level' => 'error', 'start' => '2026-01-01']) - 批量插入优先用
Db::name('user')->insertAll($data),比手写VALUES (),(),()更稳,也避开 SQL 长度限制 - 千万别混用:
Db::execute("DROP TABLE tmp")这类非事务语句,在事务块中会破坏一致性,且无法回滚
参数绑定必须用占位符,禁止字符串拼接
所有来自用户输入($_GET、$_POST、URL 参数)的值,都得进占位符;表名、字段名、ORDER BY 方向等动态部分,必须白名单校验后手动拼接。
- 高危写法(SQL 注入):
Db::query("SELECT * FROM user WHERE name = '" . $_GET['name'] . "'") - 安全写法(位置占位):
Db::query("SELECT * FROM user WHERE name = ? AND status = ?", [$name, $status]) - 安全写法(命名占位):
Db::query("SELECT * FROM user WHERE id IN ($placeholders)", $idArray)—— 注意$placeholders要提前生成如"?, ?, ?",再传对应数量的值 -
IN空数组时必须拦截:if (empty($ids)) { return []; },否则IN ()直接语法错误
事务中用原生 SQL 必须全程可控
框架不会自动判断你的原生 SQL 是否可回滚。只要没抛异常,Db::commit() 就照常提交——哪怕你执行了 ALTER TABLE 或 SET @var=1 这种没法回滚的语句。
- 必须把原生操作包在
Db::startTrans()和Db::commit()之间 - 每个
Db::query()或Db::execute()都要检查返回值,或用try-catch捕获think\db\exception\DataNotFoundException和底层 PDO 异常 - 动态
ORDER BY字段必须白名单过滤:in_array($sort, ['id', 'create_time'], true) ? $sort : 'id',再拼进 SQL - 打印最后执行 SQL 调试用:
echo Db::getLastSql();,但它只记录最后一次调用,别指望它回溯整个事务
最易被忽略的点:命名占位符和位置占位符不能混用;IN 子句的参数必须逐个绑定;事务里执行非事务语句不会报错,但会让整个事务失去原子性——这些地方不出问题则已,一出就是线上事故。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











