DB::select()仅支持SELECT查询,执行INSERT/UPDATE/DELETE需用DB::insert()、DB::update()、DB::delete()或DB::statement();参数绑定只支持?占位符,IN语句需手动拼接;务必启用查询日志调试并禁用生产环境。

可以直接用 DB::select(),但要注意它只返回结果集,不支持 INSERT/UPDATE/DELETE;执行写操作得换 DB::insert()、DB::update() 或 DB::statement()。
DB::select() 只能查,不能改数据
很多人以为 DB::select() 是“万能原生 SQL 入口”,其实它底层调用的是 PDO 的 query() + fetchAll(),仅适用于 SELECT。传入 INSERT 会报错或静默失败(取决于 PDO 设置)。
- ✅ 正确:获取用户列表
DB::select("SELECT * FROM users WHERE status = ?", [1]) - ❌ 错误:试图插入
DB::select("INSERT INTO logs (msg) VALUES (?)", ['test'])—— 不报错但无效果 - ⚠️ 注意:参数绑定只支持
?占位符,不支持命名绑定(如:name),除非你用DB::select('...', [], $options)手动传 PDO 选项
写操作必须用对应方法或 DB::statement()
原生写语句不能塞进 DB::select(),Laravel 提供了语义明确的替代:
- 插入单条且要主键:用
DB::insert()(返回 bool)或DB::table()->insertGetId() - 批量插入:用
DB::insert()配合多维数组,或DB::table()->insert() - UPDATE/DELETE:推荐
DB::update()/DB::delete(),它们返回影响行数 - 其他(如 TRUNCATE、CREATE、带变量的存储过程调用):统一走
DB::statement(),它等价于 PDOexec()
例如清空表并重置自增:DB::statement('TRUNCATE TABLE posts') —— 这个不能用 DB::delete() 替代。
防止 SQL 注入:永远别拼接字符串
哪怕看起来是“固定值”,只要含用户输入,就必须参数化。下面这些写法都危险:
- ❌
"SELECT * FROM users WHERE name = '" . $_GET['name'] . "'" - ❌
"SELECT * FROM users WHERE id IN (" . implode(',', $ids) . ")" - ✅ 安全查单个:
DB::select("SELECT * FROM users WHERE name = ?", [$name]) - ✅ 安全查多个 ID:
DB::select("SELECT * FROM users WHERE id IN (" . str_repeat('?,', count($ids) - 1) . '?)', $ids)
注意:Laravel 不自动处理 IN 的参数展开,得手动拼占位符串 —— 这是常见疏漏点。
调试时看真实 SQL 和绑定值
光看代码难定位问题,开启查询日志最直接:
- 临时启用:
DB::enableQueryLog();,之后dd(DB::getQueryLog()); - 日志里能看到完整 SQL 字符串、绑定参数、执行耗时
- ⚠️ 生产环境禁用,有性能开销;且
enableQueryLog()在某些连接池配置下可能不生效
如果看到绑定参数没替换进去(比如还是 ?),说明你用了错误的方法(如对写操作误用 select)或者 PDO 没正确设置 ATTR_EMULATE_PREPARES。
真正麻烦的不是语法,而是混用读写方法、忽略参数绑定边界、以及在复杂 IN 或动态字段场景下硬拼 SQL —— 这些地方一出错,调试成本远高于用 Query Builder。










