Laravel Eloquent如何进行原生SQL查询_执行原生数据库语句

Laravel Eloquent如何进行原生SQL查询_执行原生数据库语句
最新回答
传说甜蜜的味道

2024-02-10 16:35:35

在Laravel Eloquent中执行原生SQL查询主要通过DB门面实现,结合参数绑定防止SQL注入,同时提供灵活的方法处理各类数据库操作。

一、原生SQL执行方法
  1. 查询数据(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]);
  2. 插入数据(INSERT)

    使用DB::insert()执行INSERT语句,返回受影响的行数(通常为1)。

    $result = DB::insert( 'INSERT INTO users (name, email) VALUES (?, ?)', ['John Doe', 'john@example.com']);
  3. 更新数据(UPDATE)

    使用DB::update()执行UPDATE语句,返回受影响的行数。

    $affected = DB::update( 'UPDATE users SET votes = 100 WHERE name = ?', ['John']);
  4. 删除数据(DELETE)

    使用DB::delete()执行DELETE语句,返回被删除的行数。

    $deleted = DB::delete('DELETE FROM users WHERE active = 0');
  5. 通用语句(DDL/存储过程)

    使用DB::statement()执行不返回结果的语句(如创建表、调用存储过程)。

    DB::statement('DROP TABLE IF EXISTS old_users');DB::statement('CREATE TABLE new_users (id INT PRIMARY KEY, name VARCHAR(255))');
二、Eloquent查询中嵌入原生SQL片段
  1. DB::raw()方法

    将字符串标记为原生表达式,避免转义,用于计算字段或复杂条件。

    // 在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();
三、适用原生SQL的场景
  1. 复杂查询与报表生成

    多层嵌套子查询、复杂JOIN逻辑、窗口函数(如ROW_NUMBER())或聚合函数优化。

    Eloquent虽能实现,但原生SQL更直观且易于性能调优。

  2. 性能瓶颈优化

    精确控制索引使用、查询计划,或利用数据库特定优化技巧(如MySQL的FORCE INDEX)。

  3. 数据库特定功能

    调用PostgreSQL的JSONB操作、MySQL的GROUP_CONCAT等Eloquent不支持的功能。

  4. 遗留系统集成

    与不符合ORM规范的复杂数据库交互时,原生SQL更直接且减少适配痛苦。

  5. 调试与验证

    通过->toSql()查看Eloquent生成的SQL后,直接运行原生SQL验证逻辑。

四、安全执行原生SQL的关键:参数绑定
  1. 核心原则

    永远不要拼接用户输入到SQL字符串中,必须使用参数绑定。

    Laravel的DB门面方法(如select、insert)均支持预处理语句,自动转义参数。

  2. 正确示例

    // 错误:直接拼接用户输入(高危!)$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]);
  3. 参数绑定原理

    数据库先解析SQL结构,再填充绑定值,恶意输入(如' OR 1=1 --)会被视为普通字符串。

  4. 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();
五、权衡:Eloquent与原生SQL的选择
  • 优先Eloquent:享受自动类型转换、模型事件、关联管理等便利,提升可维护性。
  • 选择原生SQL:仅在Eloquent无法满足需求时使用(如复杂查询、性能优化、特定功能),并确保严格参数绑定。

通过合理使用DB门面和参数绑定,开发者能在Laravel中安全高效地执行原生SQL,平衡灵活性与可维护性。