Laravel如何执行原生SQL语句_Laravel DB::select用法【干货】

2次阅读

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

Laravel如何执行原生SQL语句_Laravel DB::select用法【干货】

可以直接用 DB::select(),但要注意它只返回结果集,不支持 INSERT/UPDATE/DELETE;执行写操作得换 DB::insert()DB::update()DB::statement()

DB::select() 只能查,不能改数据

很多人以为 DB::select() 是“万能原生 sql 入口”,其实它底层调用的是 pdoquery() + 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(),它等价于 PDO exec()

例如清空表并重置自增: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。

text=ZqhQzanResources