75142913在线留言
【Laravel笔记】内置数据库关系映射器(ORM): Eloquent 使用快速入门_PHP技术_网络人

【Laravel笔记】内置数据库关系映射器(ORM): Eloquent 使用快速入门

Kwok 发表于:2022-04-05 18:05:09 点击:50 评论: 0

Eloquent 是Laravel内置的一个功能强大的数据库关系映射器,通过use Illuminate/Database/Eloquent/Model;引用其内置的各项强大的方法对数据库实现更优雅的CRUD操作。

Eloquent和前面说到的查询构造器功能相似,Eloquent的出现是为了让程序员只需要注重代码层面的工作,无需过多的了解SQL语言,Laravel将我们常用的SQL语句封装成了可以通过语义变成更可读的程序操作。

下面列出常用的模型方法,以快速了解我们的需要,并对照官方文档了解详细使用方法:

  1. .find($primaryKey) 查找单条 主键=$primaryKey ( where id = 1 limit 1)
  2. .find([1,2,3])  通过数组参数 查找 多条,( where id in(1,2,3) )
  3. .first() 查找并只返回1条 LIMIT 1
  4. .firstWhere() 带条件查询并只返回1条 (where('user_id', 1)->first()的快速写法)
  5. .firstOr() 查找首个返回,支持闭包
  6. .firstOrFail() 找不到时返回异常
  7. .count() 返回查询结果统计数
  8. .max() 返回最大数 等更多参考集合

ORM用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。Laravel对语法深入优化,所以在执行效率上更接近原生SQL,与查询构造器的区别基本上就只有在程序逻辑层面,在使用了Opcache的情况下效果几乎感觉不到差异,所以为了我们更高的可维护性与编程,我们更应该去使用Eloquent。

一、使用Eloquent前的准备工作

在使用Eloquent前我们需要有一些前置准备条件,与查询构造器一样,首先我人需要保证其数据库连接的可用性。然后根据下面的步骤对MVC构架做初始化的工作。

请先使用数据库迁移功能创建Model与迁移表,并使用命令创建我们将要操作的数据表工作,参考:http://www.55mx.com/php/209.html

二、模型对数据库的基本操作

通过上面提供的参考方法创建了一个模型和其关联的数据库表后,就可以开始从数据库中检索数据了。

1、检索数据库表里所有行

我们可以将Eloquent视为一个强大的 查询构建器 ,可以让我们流畅的查询与模型关联的数据表,模型中的all方法可以从模型的关联数据库表中检索出所有的记录:

use AppModelsSetting; //引入我们准备工作里的模型
class ShowController extends Controller
{
    public function show()
    {
        //Setting::all() = select * from settings
        foreach (Setting::all() as $setting) { //返回一个查询结果对象
            echo $setting->key;//使用对象属性 访问键值
            echo $setting->value;
        }
    }
}

上面控制器代码里可以看到没有一行SQL语句的影子,但从数据库里获取到了设置项的所有内容。Eloquent 的 all() 方法会返回模型中所有的结果。

小提示:使用Setting::all()与Setting::get()得到的结果是一模一样的,并且生成的查询语句也是一样的,它们的区别在于Setting::all()是一个快速方式,直接返回了查询后的结果集,中间不能再使用排序、条件等限制,而下面我们要使用的Setting::get()方法则更灵活,所以它们的区别在于是否可以附件更多的条件限制。

2、使用条件限制

由于每个 Eloquent 模型都可以被视为 查询构造器,可以添加额外的查询条件,然后使用 get() 方法获取查询结果:

public function show()
{
    $Setting = Setting::where('value', 1) //查询value = 1的数据
        ->orderBy('key') //使用key排序
        ->take(10) //返回10条数据
        ->get(); //查询结果转对象
    //->toSql(); //select * from `kwok_settings` where `value` = ? order by `key` asc limit 10 
    return $Setting->toJson(); //使用集合辅助功能转为Json
}

Eloquent Collection 类扩展了 Laravel 的 Illuminate/Support/Collection 基类,它提供了 大量的辅助方法 来与数据集合交互。

3、刷新模型

如果已经有一个从数据库中检索到的 Eloquent 模型的实例,你可以使用 fresh 和 refresh 方法「刷新」模型。 fresh 方法将从数据库中重新检索模型。现有模型实例不会受到影响:

public function show()
{
    $Setting = Setting::where('value', '>', 1)->first();
    echo $Setting->key; //输出数据库里的结果
    echo $Setting->key = '改了';//输出修改后的结果
    $freshSetting = $Setting->fresh(); //将刷新后的模型(重新执行Sql语句)交给新的变量
    echo $freshSetting; //打印新变量的结果(数据库里的结果)
}

上面代码里我们将重新查询的结果赋予了新的变量,如果我只想要直接刷新当前的模型,只需要使用refresh即可,上面的代码重写为:

public function show()
{
    $Setting = Setting::where('value', '>', 1)->first();
    echo $Setting->key; //输出数据库里的查询结果
    echo $Setting->key = '改了'; //输出修改后的结果
    $Setting->refresh(); //直接当前模型刷新模型(重新执行Sql语句)
    echo $Setting; //输出结果(数据库里的结果)
}

 refresh 方法会使用数据库中的新数据重新赋值现有的模型。此外,已经加载的关系也会被重新加载。Eloquent 是继承于 IlluminateDatabaseEloquentCollection 集合,并扩展了自己一些独有的方法。

4、结果分块

当前我们查询的表里数据量过大时,使用->all()方法或者get()方法的时候,会大量占用服务器的资源,和查询构造器一样,Eloquent也提供chunk()方法,使用分块数据查询:

//每次获取10条数据
Setting::chunk(10, function ($settings) {
    //获取到数据后传递给闭包处理
    echo '<h2>分块了</h2>';
    //使用each 代替foreach方法遍历集合
    $settings->each(function ($item, $key) {
        echo '<li>' .  $key . '=>' . $item . '</li>';
    });
});

传递给「chunk」方法的第一个参数是每个分块检索的数据数量。第二个参数传递的闭包将方法将应用到每个分块,以数据库中查询到的分块结果来作为参数。

5、按条件分块

如果要根据一个字段来过滤「chunk」方法拿到的数据,同时,这个字段的数据在遍历的时候还需要更新的话,那么可以使用「chunkById」方法。在这种场景下如果使用「chunk」方法的话,得到的结果可能和预想中的不一样。在「chunkById」 方法的内部,默认会查询 id 字段大于前一个分块中最后一个模型的 id。

Setting::where('value', true)
    ->chunkById(10, function ($setting) {
        echo $setting;//输出查询结果
    }, $column = 'key');

 6、惰性集合分块

使用惰性lazy()方法在后台以块的形势执行查询操作,lazy不是将每个块直接传递到闭包回调中,而以返回 Eloquent 模型的扁平化 LazyCollection,它可以让你将结果作为单个流进行交互:

echo '<ol>';
foreach (Setting::lazy() as $setting) {
    echo '<li>' . $setting . '</li>';
}

如果要根据一个字段来过滤「lazy」方法拿到的数据,同时,这个字段的数据在遍历的时候还需要更新的话,那么可以使用「lazyById」方法。在「lazyById」 方法的内部,默认会查询 id 字段大于前一个「chunk」中最后一个模型的 id 。

Setting::where('value', 1)
    ->lazyById(10, $column = 'key')
    ->each(function ($item) {
        echo '' . $item . '';
    });

lazy使用可以用于加载数据关系,并有很好的性能,比较推荐使用!

7、游标

与 lazy 方法类似,cursor 方法可用于在查询数万条 Eloquent 模型记录时减少内存的使用。

cursor 方法只会执行一次数据库查询;但是,各个 Eloquent 模型在实际迭代之前不会被数据填充。因此,在遍历游标时,在任何给定时间,只有一个 Eloquent 模型保留在内存中。

foreach (Setting::where('value', '1')->cursor() as $setting) {
    echo $setting;
}

cursor 方法一次只能在内存中保存一个 Eloquent 模型。使用后就自由回收内存。但值得注意的是在查询大量数据时它最终仍会耗尽内存。如果要处理大量 Eloquent 记录,请考虑使用上面的 lazy 方法。

三、插入、修改与删除

相比上面的查询,插入、修改与删除要简单许多,也提供了封装好的各种方法供我们使用。

1、插入数据

只需要实例化一个新模型实例并在模型上设置属性。然后,在模型实例上调用 save 方法: 

$setting = new Setting;//初始化一个Setting实例
$setting->key = 'imgzip';//图片压缩
$setting->value = 95;//图片压缩率
$setting->save();//保存修改

使用create方法可以快捷操作插入,如果我们未设置的情况下,这2个方法都会自动维护updated_at与created_at字段:

$setting = Setting::create([
    'key' => 'wapurl',
    'value' => 'https://m.meishiq.com/',
]);
//使用create方法将自动写入到数据表里,无需调用 save方法

以上2种插入数据的方式,可以根据我们的需求选择,一般情况第一种方式更适用于需要修改Model参数时使用($setting->timestamps = true)。同时下面的更新操作也是使用此方式。

2、更新数据

我们在更新数据之前,应该先根据条件查找到需要更新的内容:

$setting = Setting::find('timeoffset');//查找到key = timeoffset的值
$setting->value = 8;//修改时区
$setting->save();//保存修改

 当$timestamps=true时,此操作会自动维护updated_at字段的时间。

除了上面的单个数据更新,我们也可以使用批量的更新操作:

Setting::where('value', 1) //找到所有value=1的值
      ->update(['value' => -1]);//改为:-1

update 方法需要一个表示应该更新的列的列和值对数组。 update 方法返回受影响的行数。

注意:通过 Eloquent 批量更新时,不会触发模型的 saving、saved、updating 和 updated 模型事件。 这是因为在批量更新时从未真正检索到模型。

3、新增或更新

有时候,我们需要使用一个值插入到数据库里,如果此值存在的情况下,我们就更新,否则插入,这样我们就需要updateOrCreate方法来实现:

$setting = Setting::updateOrCreate(
    ['sitemap_num' => 10000],//单个文件生成sitemap的数量
    ['price' => 99]//商品价格
);

4、删除数据

删除操作提供了多种灵活的方式,我们可以根据情况选择性使用:

//查询并删除
$Setting = Setting::find('url');
$Setting->delete();
//按条件批量删除
$deleted = Setting::where('value', 0)->delete();//删除所有value=0的值

通过主建删除:

Setting::destroy('imgzip');//单个删除
//多个删除
Setting::destroy('url','wapurl');
Setting::destroy(['url','wapurl']);
Setting::destroy(collect(['url','wapurl']));

清空表:

Setting::truncate();//清空此表自增ID初始化

5、软删除

上面的方式是直接将数据从表中清除,但有时候我们还希望能恢复被删除的数据,所以我们需要在表中指定一个字段:deleted_at,以记录软删除的时间。

如果要使用软删除功能,我们需要在Model里打开属性开关:

use IlluminateDatabaseEloquentSoftDeletes;//使用软删除
class Setting extends Model
{
    use SoftDeletes;//打开软删除开关
}
//技巧:SoftDeletes trait 会自动将 deleted_at 属性转换为 DateTime / Carbon 实例。

然后需要增加软删除必备的字段,下面以迁移演示:

Schema::table('Setting', function (Blueprint $table) {
    $table->softDeletes();
});

Schema::table('Setting', function (Blueprint $table) {
    $table->dropSoftDeletes();
});

判断是否被软删除,可以使用trashed方法:

if ($setting->trashed()) {
    //被删除了
   $setting->restore();//恢复被删除
}

批量恢复被软删除的数据:

Setting::withTrashed()
        ->where('value', 1)
        ->restore();
//和其他「批量」操作一样,这个操作不会触发模型的任何事件

$setting->history()->restore();//可以在 关联查询 中使用

将软删除的数据真正删除:

$setting->forceDelete();//硬删除所有被软删除的数据
$setting->history()->forceDelete();//在关联查询上使用

软删除并不是真正的删除,只是标记了删除时间,当使用模型查询数据时,将自动排队被软删除的数据。

四、模型查询优化

模型虽好用,但查询语法并不是最优化的,我们应该尽量避免使用一些大量耗费服务器资源的查询,下面个人总结了一些查询优化以供参考:

1、限制查询字段

上面语句大部分都是使用select * 来查询数据库的,很多时候我们并不需要 这么多的字段,所以我们可以使用select方法限制查询的字段:

echo Setting::select('key', 'value')->where('value', '1')->toSql();
//select `key`, `value` from `kwok_settings` where `value` = ?

使用all、get、first时可以使用参数限制column字段名:

Setting::all('key', 'value');//select `key`, `values` from `kwok_settings`
Setting::get(['key', 'value']);//select `key`, `values` from `kwok_settings`
//find方法限制字段
Setting::find(['allowcache', 'sitename', 'seotitle'], ['key', 'value']);
//select `key`, `value` from `kwok_settings` where `kwok_settings`.`key` in (allowcache, sitename, seotitle)
//获取单个字段时使用
Setting::where('key', 'allowcache')->value('value');
//select `value` from `kwok_settings` where `key` = allowcache limit 1

//使用pluck方法限制
Setting::where('key', 'allowcache')->pluck('key', 'values');
//select `key`, `values` from `kwok_settings` where `key` = allowcache

//使用findOrFail的第二个参数
Setting::findOrFail('allowcache', ['key', 'value']);
//select `key`, `value` from `kwok_settings` where `kwok_settings`.`key` = allowcache limit 1

获取查询语句的小技巧:我在网上搜索了很多,有的推荐使用toSql()方法,但很多都不能获取,所以我故意将字段写错,比如上面的value我改成values时Laravel就会报错,在错误里就可以看到SQL语句了。

如果你有更好的查询语句获取方法,可以通过评论告诉我。

除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/208
标签:eloquentORM数据库Kwok最后编辑于:2022-04-12 11:12:38
0
感谢打赏!

《【Laravel笔记】内置数据库关系映射器(ORM): Eloquent 使用快速入门》的网友评论(0)

本站推荐阅读

热门点击文章