Laravel 查询构造器不是 ORM,它生成并执行原生 SQL,避免字符串拼接和 SQL 注入风险(前提不手动拼接用户输入);基础 SELECT 用 DB::table() 链式调用后加 get() 或 first() 才执行。

直接说结论:Laravel 查询构造器(Query Builder)不是 ORM,它生成并执行原生 SQL,但帮你省去了字符串拼接和 SQL 注入风险——前提是别手动拼接 $request->input('sort') 这种值。
怎么写最基础的 SELECT 查询
用 DB::table() 开头,链式调用方法,最后加 get() 或 first() 才真正执行:
use Illuminate\Support\Facades\DB;
<p>$users = DB::table('users')->where('active', 1)->orderBy('created_at', 'desc')->get();
$user = DB::table('users')->where('id', 5)->first(); // 返回单条记录(stdClass 对象)
</p>
-
get()返回Illuminate\Support\Collection,可直接遍历;first()返回单个对象或null - 不加
get()/first()等终止方法,查询根本不会执行——这是常见“查不到数据”却没报错的原因 - 所有
where()条件默认是 AND;想 OR 就得用orWhere(),但注意括号优先级,复杂条件建议用闭包分组
WHERE 条件里容易踩的坑
看似简单的 where(),实际参数组合多、行为差异大:
-
where('status', 'published')→ 等价于= -
where('price', '>', 100)→ 第二个参数是操作符,必须带引号 -
whereBetween('created_at', ['2024-01-01', '2024-12-31'])→ 闭区间,含两端 -
whereIn('id', [1, 2, 3])→ 数组长度超 1000 时,部分 MySQL 版本会报SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders,需分批查 - 千万别这样写:
where('name', $_GET['name'])—— 这绕过了 Laravel 的绑定机制,直接导致 SQL 注入
JOIN 和子查询怎么写才安全
JOIN 不难,但字段冲突和子查询嵌套容易出错:
DB::table('orders')
->join('users', 'users.id', '=', 'orders.user_id')
->select('orders.*', 'users.name as user_name')
->where('users.active', 1)
->get();
- 显式指定
select()字段,避免*导致字段名重复(比如两个表都有id) - 子查询要用
fromSub()或闭包传入table(),不能直接塞字符串:DB::table(DB::raw('(SELECT * FROM logs WHERE type = "error") as errors'))是错的,应改用fromSub(..., 'errors') - LEFT JOIN 用
leftJoin(),RIGHT JOIN 极少用,Laravel 官方也不鼓励
UPDATE / DELETE 必须加 WHERE,否则全表扫雷
构造器执行写操作不会自动加防护,update() 和 delete() 默认作用于整个表:
-
DB::table('posts')->update(['published' => false]);→ 没有 WHERE?所有文章都被设为未发布 - 正确做法:先用
where()锁定范围,再调用update()或delete() - 想看 SQL 长啥样但不执行?用
toSql():DB::table('users')->where('id', 1)->toSql()输出"select * from `users` where `id` = ?" - 批量更新大表时,
update()会锁表,线上慎用;高频场景建议改用原生语句 +DB::unprepared()分批次处理
真正麻烦的从来不是语法怎么写,而是忘记加 where()、误信用户输入、或者在事务外执行了不可回滚的写操作——这些错误不会报语法异常,但会让数据出问题。











