Laravel 11 查询构建器基础

查询构建器(Query Builder)是 Laravel 提供的用于数据库交互的流畅接口,它允许你使用 PHP 方法链来构建 SQL 查询,同时自动防止 SQL 注入。 相比原生 SQL,查询构建器更安全、更易读,并且与数据库无关。

🎯 什么是查询构建器?

查询构建器位于 Illuminate\Database\Query\Builder 类中,通过 DB Facade 的 table 方法获取实例。 它支持几乎所有 SQL 操作,并提供了流畅的链式调用语法。

💡 优势: 查询构建器会自动对输入进行参数绑定,有效防止 SQL 注入;同时其语法统一,可以在 MySQL、PostgreSQL、SQLite 等数据库间无缝切换。

📥 获取查询构建器实例

使用 DB::table() 方法,传入表名,即可获得该表的查询构建器实例:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')->get();

📖 基础查询操作

1. 获取所有记录

get() 方法返回一个包含所有查询结果的集合(Collection),每条记录是一个 PHP 对象:

$users = DB::table('users')->get();
foreach ($users as $user) {
    echo $user->name;
}
2. 获取单条记录

first() 方法只返回结果集的第一条,没有记录时返回 null

$user = DB::table('users')->where('id', 1)->first();
echo $user->name;

还可以使用 find($id) 直接根据主键查找:

$user = DB::table('users')->find(1);
3. 获取特定列

value() 方法返回单条记录的单个字段值:

$email = DB::table('users')->where('name', 'John')->value('email');

pluck() 方法获取一列的值,返回集合:

$names = DB::table('users')->pluck('name');
// ['John', 'Jane', ...]

// 可指定键名
$users = DB::table('users')->pluck('name', 'id');
// [1 => 'John', 2 => 'Jane', ...]

🔍 条件子句

1. where 条件

基本 where 方法接受三个参数:字段、操作符、值:

$users = DB::table('users')
            ->where('age', '>', 18)
            ->get();

如果只传两个参数,操作符默认为 =

$users = DB::table('users')->where('active', 1)->get();
2. 多个 where 条件

可以链式调用多个 where,它们默认使用 AND 连接:

$users = DB::table('users')
            ->where('active', 1)
            ->where('age', '>=', 18)
            ->get();
3. orWhere 条件

orWhere 用于添加 OR 条件:

$users = DB::table('users')
            ->where('active', 1)
            ->orWhere('age', '>=', 18)
            ->get();
4. 高级 where 子句

whereBetweenwhereInwhereNull 等:

// 范围查询
$users = DB::table('users')->whereBetween('age', [18, 30])->get();

// IN 查询
$users = DB::table('users')->whereIn('id', [1, 2, 3])->get();

// NULL 查询
$users = DB::table('users')->whereNull('email_verified_at')->get();

// 日期查询
$users = DB::table('users')->whereDate('created_at', '2024-01-01')->get();
5. 条件分组

使用闭包创建嵌套的 where 条件:

$users = DB::table('users')
            ->where('active', 1)
            ->where(function ($query) {
                $query->where('age', '>', 30)
                      ->orWhere('name', 'like', 'John%');
            })
            ->get();

生成的 SQL:SELECT * FROM users WHERE active = 1 AND (age > 30 OR name LIKE 'John%')

📊 聚合函数

查询构建器提供了 countmaxminavgsum 等聚合方法:

$count = DB::table('users')->count();                 // 总记录数
$maxAge = DB::table('users')->max('age');             // 最大年龄
$avgScore = DB::table('scores')->avg('score');        // 平均分
$total = DB::table('orders')->sum('amount');          // 总金额

📈 排序、分组与限制

1. 排序

orderBy 方法:

$users = DB::table('users')
            ->orderBy('name', 'asc')
            ->orderBy('age', 'desc')
            ->get();
2. 分组与 having
$users = DB::table('users')
            ->select('department', DB::raw('count(*) as total'))
            ->groupBy('department')
            ->having('total', '>', 10)
            ->get();
3. 限制条数

take / limitskip / offset

$users = DB::table('users')->limit(10)->get();          // 取前10条
$users = DB::table('users')->skip(5)->take(10)->get();  // 跳过5条,取10条

✍️ 插入、更新、删除

1. 插入数据

使用 insert 方法插入单条或多条记录:

// 单条
DB::table('users')->insert([
    'name' => 'John',
    'email' => 'john@example.com',
    'age' => 25
]);

// 多条
DB::table('users')->insert([
    ['name' => 'John', 'email' => 'john@example.com'],
    ['name' => 'Jane', 'email' => 'jane@example.com']
]);

使用 insertGetId 获取自增 ID:

$id = DB::table('users')->insertGetId([
    'name' => 'John',
    'email' => 'john@example.com'
]);
2. 更新数据

使用 update 方法,返回受影响的行数:

$affected = DB::table('users')
                ->where('id', 1)
                ->update(['age' => 30]);

可以使用 incrementdecrement 快捷增减:

DB::table('users')->where('id', 1)->increment('age', 2);   // age + 2
DB::table('users')->where('id', 1)->decrement('age');       // age - 1
// 同时更新其他字段
DB::table('users')->where('id', 1)->increment('age', 1, ['updated_at' => now()]);
3. 删除数据

delete 方法删除记录,返回受影响行数:

$deleted = DB::table('users')->where('id', 1)->delete();

清空表使用 truncate

DB::table('users')->truncate();

🧩 原生表达式

当需要执行原生 SQL 函数或特定数据库语法时,可以使用 DB::raw()

$users = DB::table('users')
            ->select(DB::raw('count(*) as user_count, status'))
            ->groupBy('status')
            ->get();

但需要注意,raw 的内容不会被参数绑定,存在 SQL 注入风险,应谨慎使用。Laravel 也提供了更安全的方法,如 whereRaworderByRaw 等:

$users = DB::table('users')
            ->whereRaw('age > ? and active = ?', [18, 1])
            ->get();

🐞 调试与日志

可以使用 toSql() 获取当前查询的 SQL 语句(不带参数绑定):

$sql = DB::table('users')->where('id', 1)->toSql();
// select * from users where id = ?

要查看完整的 SQL 和绑定的参数,可以使用 dd()dump() 配合 get() 等执行方法:

DB::table('users')->where('id', 1)->dd(); // 输出 SQL 和参数并终止
DB::table('users')->where('id', 1)->dump(); // 仅输出,继续执行

还可以启用查询日志:

DB::enableQueryLog();
$users = DB::table('users')->get();
$queries = DB::getQueryLog(); // 返回所有执行过的查询数组

🎨 实战示例:用户管理

结合所学知识,构建一个简单的用户管理功能:

// 获取所有活跃用户,按年龄降序,取前10名
$activeUsers = DB::table('users')
    ->where('active', 1)
    ->orderBy('age', 'desc')
    ->limit(10)
    ->get();

// 插入新用户
$newUserId = DB::table('users')->insertGetId([
    'name' => 'New User',
    'email' => 'new@example.com',
    'active' => 1,
    'created_at' => now(),
]);

// 更新用户邮箱
DB::table('users')
    ->where('id', $newUserId)
    ->update(['email' => 'updated@example.com']);

// 删除不活跃用户
$deleted = DB::table('users')
    ->where('active', 0)
    ->delete();
⚠️ 注意: 查询构建器默认不会对表名或字段名进行转义,如果表名或字段名是保留字,应使用 DB::raw 或确保名称正确。

❓ 常见问题

查询构建器返回的是普通的 PHP 对象(stdClass),而 Eloquent 返回的是模型实例,包含关系、访问器等高级功能。查询构建器更轻量,适合复杂查询或不需要模型功能的场景。

查询构建器通过参数绑定自动转义所有传入的值,因此使用 whereinsert 等方法时是安全的。但使用 DB::rawwhereRaw 时需手动处理参数绑定。

可以使用 toSql() 获取带占位符的 SQL,或者使用 dd()dump() 查看带绑定的完整 SQL。也可以启用查询日志 DB::enableQueryLog() 并获取 DB::getQueryLog()

📝 小结

查询构建器是 Laravel 中处理数据库查询的核心工具,它提供了流畅的接口和丰富的条件方法,让开发者能够轻松构建复杂的 SQL 语句。 掌握这些基础操作后,下一章我们将学习更高级的查询技巧,如连接查询、子查询、联合查询等。