
laravel eloquent orm 提供了一种优雅的方式与数据库进行交互。find() 方法是 eloquent 中最常用的查询方法之一,它用于根据主键(通常是 id 字段)检索单个模型实例。当调用 flight::find(1) 时,eloquent 会构建一个sql查询,大致相当于 select * fromflightswhereflights.id= 1 limit 1,然后执行此查询并返回匹配的记录。如果找到记录,eloquent 会将其封装成一个 flight 模型对象实例;如果未找到,则返回 null。
一个常见的误解是,如果对同一个主键多次调用 find() 方法,Laravel 会智能地缓存结果,从而只执行一次数据库查询。然而,事实并非如此。Laravel Eloquent 默认情况下不会为单个 find() 调用提供这种内置的、跨多次调用的结果缓存。
考虑以下代码片段:
use App\Models\Flight; $a = Flight::find(1); $b = Flight::find(1);
在这种情况下,将会执行两次独立的数据库查询。
这两次查询是独立的,因为 Eloquent 在每次调用 find() 时都会重新构建并执行查询,它不会在内部自动记录之前查询过的特定主键的结果。
除了查询次数,理解对象实例化也同样重要。对于上述代码:
use App\Models\Flight; $a = Flight::find(1); $b = Flight::find(1);
将会创建两个独立的 Flight 模型对象实例。
这意味着 $a 和 $b 是内存中两个不同的对象实例,尽管它们可能包含完全相同的数据(即它们的属性值都相同)。通过 PHP 的严格比较运算符 === 可以验证这一点:$a === $b 将返回 false。
以下代码演示了查询和对象创建的行为:
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
30
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB; // 用于监听数据库查询
class Flight extends Model
{
protected $fillable = ['name']; // 示例字段
}
// 假设数据库中存在 id 为 1 的 Flight 记录
// 监听数据库查询事件,以便统计或打印查询
$queries = [];
DB::listen(function ($query) use (&$queries) {
$queries[] = $query->sql;
echo "执行 SQL: " . $query->sql . " (绑定参数: " . json_encode($query->bindings) . ")\n";
});
echo "--- 第一次 Eloquent find() 调用 ---\n";
$a = Flight::find(1);
echo "--- 第二次 Eloquent find() 调用 ---\n";
$b = Flight::find(1);
echo "\n--- 结果分析 ---\n";
echo "总共执行了 " . count($queries) . " 次数据库查询。\n"; // 输出 2
echo "变量 \$a 是否是 Flight 模型的实例? " . ($a instanceof Flight ? '是' : '否') . "\n"; // 输出 '是'
echo "变量 \$b 是否是 Flight 模型的实例? " . ($b instanceof Flight ? '是' : '否') . "\n"; // 输出 '是'
echo "变量 \$a 和 \$b 是否指向同一个对象? " . ($a === $b ? '是' : '否') . "\n"; // 输出 '否'
echo "变量 \$a 和 \$b 的 ID 是否相同? " . ($a->id === $b->id ? '是' : '否') . "\n"; // 输出 '是'
// 假设 Flight 模型有一个 'name' 属性
if ($a && $b) {
echo "变量 \$a 的名称: " . $a->name . "\n";
echo "变量 \$b 的名称: " . $b->name . "\n";
}
/*
预期输出示例(具体SQL可能因Laravel版本和DB驱动略有不同):
--- 第一次 Eloquent find() 调用 ---
执行 SQL: select * from `flights` where `flights`.`id` = ? limit 1 (绑定参数: [1])
--- 第二次 Eloquent find() 调用 ---
执行 SQL: select * from `flights` where `flights`.`id` = ? limit 1 (绑定参数: [1])
--- 结果分析 ---
总共执行了 2 次数据库查询。
变量 $a 是否是 Flight 模型的实例? 是
变量 $b 是否是 Flight 模型的实例? 是
变量 $a 和 $b 是否指向同一个对象? 否
变量 $a 和 $b 的 ID 是否相同? 是
变量 $a 的名称: Flight Name 1
变量 $b 的名称: Flight Name 1
*/这种行为在开发过程中需要注意,尤其是在循环或频繁获取相同数据的情况下:
为了避免不必要的重复查询和对象创建,可以采取以下策略:
复用已获取的对象:如果确定需要在同一请求生命周期内多次使用同一个模型实例,最直接的方法是将第一次查询的结果存储在一个变量中,然后复用该变量。
$flight = Flight::find(1); // 只执行一次查询,创建一次对象 // ... 使用 $flight // ... 再次使用 $flight
应用层缓存:对于不经常变化但又频繁访问的数据,可以考虑使用 Laravel 的缓存系统(如 Redis、Memcached 或文件缓存)来存储查询结果。
use Illuminate\Support\Facades\Cache;
$flight = Cache::remember('flight_1', 60, function () {
return Flight::find(1);
});
// 在接下来的 60 秒内,对 'flight_1' 的请求将从缓存中获取,不会触及数据库查询优化:对于集合操作,确保使用 eager loading(with() 方法)来避免 N+1 查询问题,但这与单个 find() 方法的场景略有不同。
Laravel Eloquent 的 find() 方法在每次调用时都会独立执行数据库查询并创建新的模型对象实例。理解这一机制对于编写高效、资源友好的 Laravel 应用程序至关重要。通过合理地复用对象或利用缓存机制,可以有效减少数据库负载和内存消耗,从而提升应用程序的整体性能。
以上就是深入理解 Laravel Eloquent find():查询次数与对象实例化的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号