2024-02-10 16:35:35
在Laravel Eloquent中执行原生SQL查询主要通过DB门面实现,结合参数绑定防止SQL注入,同时提供灵活的方法处理各类数据库操作。
一、原生SQL执行方法查询数据(SELECT)
使用DB::select()执行SELECT语句,返回stdClass对象数组。
支持参数绑定(问号占位符或命名绑定),避免SQL注入。
// 问号占位符绑定$users = DB::select('SELECT * FROM users WHERE active = ?', [1]);// 命名绑定$users = DB::select('SELECT * FROM users WHERE active = :active', ['active' => 1]);插入数据(INSERT)
使用DB::insert()执行INSERT语句,返回受影响的行数(通常为1)。
$result = DB::insert( 'INSERT INTO users (name, email) VALUES (?, ?)', ['John Doe', 'john@example.com']);更新数据(UPDATE)
使用DB::update()执行UPDATE语句,返回受影响的行数。
$affected = DB::update( 'UPDATE users SET votes = 100 WHERE name = ?', ['John']);删除数据(DELETE)
使用DB::delete()执行DELETE语句,返回被删除的行数。
$deleted = DB::delete('DELETE FROM users WHERE active = 0');通用语句(DDL/存储过程)
使用DB::statement()执行不返回结果的语句(如创建表、调用存储过程)。
DB::statement('DROP TABLE IF EXISTS old_users');DB::statement('CREATE TABLE new_users (id INT PRIMARY KEY, name VARCHAR(255))');将字符串标记为原生表达式,避免转义,用于计算字段或复杂条件。
// 在SELECT子句中使用$users = DB::table('users') ->select('name', DB::raw('COUNT(*) as user_count')) ->where('active', 1) ->groupBy('name') ->get();// 在WHERE条件中使用`whereRaw`$users = DB::table('users') ->whereRaw('age > ? AND votes < ?', [25, 100]) ->get();复杂查询与报表生成
多层嵌套子查询、复杂JOIN逻辑、窗口函数(如ROW_NUMBER())或聚合函数优化。
Eloquent虽能实现,但原生SQL更直观且易于性能调优。
性能瓶颈优化
精确控制索引使用、查询计划,或利用数据库特定优化技巧(如MySQL的FORCE INDEX)。
数据库特定功能
调用PostgreSQL的JSONB操作、MySQL的GROUP_CONCAT等Eloquent不支持的功能。
遗留系统集成
与不符合ORM规范的复杂数据库交互时,原生SQL更直接且减少适配痛苦。
调试与验证
通过->toSql()查看Eloquent生成的SQL后,直接运行原生SQL验证逻辑。
核心原则
永远不要拼接用户输入到SQL字符串中,必须使用参数绑定。
Laravel的DB门面方法(如select、insert)均支持预处理语句,自动转义参数。
正确示例
// 错误:直接拼接用户输入(高危!)$name = $_GET['name'];$users = DB::select("SELECT * FROM users WHERE name = '$name'"); // SQL注入风险!// 正确:使用参数绑定$name = $_GET['name'] ?? 'Guest';$users = DB::select('SELECT * FROM users WHERE name = ?', [$name]);// 或命名绑定$email = $_GET['email'] ?? 'guest@example.com';$user = DB::select('SELECT * FROM users WHERE email = :email', ['email' => $email]);参数绑定原理
数据库先解析SQL结构,再填充绑定值,恶意输入(如' OR 1=1 --)会被视为普通字符串。
DB::raw()的注意事项
DB::raw()不自动转义,若包含用户输入需手动清理:
// 错误:直接使用用户输入$input = $_GET['sort']; // 用户可能输入恶意字段名$users = DB::table('users')->orderBy(DB::raw($input))->get(); // 高危!// 正确:验证输入或使用白名单$allowedColumns = ['name', 'created_at'];$sort = in_array($input, $allowedColumns) ? $input : 'name';$users = DB::table('users')->orderBy(DB::raw($sort))->get();通过合理使用DB门面和参数绑定,开发者能在Laravel中安全高效地执行原生SQL,平衡灵活性与可维护性。