跳至正文

Eloquent ORM 解析入门

参考链接https://learnku.com/docs/laravel/5.5/eloquent/1332

Laravel 的 Eloquent ORM 提供了漂亮、简洁的 ActiveRecord 实现来和数据库交互。每个数据库表都有一个对应的「模型」用来与该表交互。你可以通过模型查询数据表中的数据,并将新记录添加到数据表中。

在开始之前,请确保在 config/database.php 中配置数据库连接。更多关于数据库的配置信息,请查看 文档

艺术,优雅,强大,用过的都说好!

Eloquent 模型约定

数据表名 默认使用模型类的复数形式「蛇形命名」来作为表名 ,否则使用定义的 table属性

protected $connection = 'connection-name';//此模型的连接名称
protected $table = 'my_flights';//表名
 public $timestamps = false; //关闭自己动维护时间戳
 protected $dateFormat = 'U'; //模型日期字段存储格式 U表示unix时间戳
 const CREATED_AT = 'creation_date';  //自定义创建时间字段
 const UPDATED_AT = 'last_update';  //自定义更新时间字段
protected $primaryKey = 'id'; // 定义主键字段
protected $keyType = 'int'; //主键类型
public $incrementing = true; //是否开启auto-incrment 自增属性
 protected $fillable = []; // 可以被批量赋值的属性
 
 protected $guarded = [];  // 不可批量复制的属性
  protected $casts = ['is_admin'=>'boolean'];
  //属性转换配合修改器使用时要保持类型一致
  //转换成数组或json时的可见性
  protected $visible = ['first_name', 'last_name'];//显示
  //方法显示
  $model->makeVisible('attribute')->toArray();
  protected $hidden = ['password'];//隐藏
  //方法隐藏
  $model->makeHidden('attribute')->toArray();
protected $appends = ['is_admin']; //追加到模型数组表单的访问器。
//配合访问器
public function getIsAdminAttribute()
{
   return $this->attributes['admin'] == 'yes';
}
//运行时追加
return $model->append('is_admin')->toArray();

return $model->setAppends(['is_admin'])->toArray();

模型方法

模型的查询构造器中注入了DB的查询构造器,所以模型也支持DB查询构造器的方法.这里只解析模型查询构造器的独有方法或模型和DB的特殊方法

all() 查询所有

$flights = App\Flight::all();//查询所有结果
模型内方法,实际调用的是DB的get方法,参数是字段支持数组和多个参数形式
all方法直接创建了一个查询构造器然后执行get()方法,所以调用all方法之前无法调用任何查询构造器的方法
public static function all($columns = ['*'])
{
     return (new static)->newQuery()->get(
         is_array($columns) ? $columns : func_get_args()
     );
}

cursor() 游标遍历,适用于大数据量处理.


foreach (User::select('id', 'name')->cursor() as $user) {
   //处理操作    
   dump($user);
}

内部实现使用PHP generator 进行遍历 生成器是协程调度, 耗时和消耗内存是恒定的(接近),跟数据量无关.

 /**
  * Get a generator for the given query.
  *
  * @return \Generator
  */
public function cursor()
{
     foreach ($this->applyScopes()->query->cursor() as $record) {
         yield $this->model->newFromBuilder($record);
     }
}

chunk() 分块处理 适用于小数据量快速处理

Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});

内部实现 do while 循环 执行的分页查询sql 耗时和消耗内存取决分块数量,分块数量越大消耗内存和耗时相应减少

select * from `flights` order by `flights`.`id` asc limit 200 offset 0  
select * from `flights` order by `flights`.`id` asc limit 200 offset 200  
select * from `flights` order by `flights`.`id` asc limit 200 offset 400  

附上测试代码

//内存计算函数
function print_memory_info($msg, $real_usage = false)
{
    echo $msg, ceil(memory_get_usage($real_usage) / 1024), 'KB', '<br>';

    return memory_get_usage($real_usage);
}

//使用游标方式
public function test1(Request $request)
{
        $start_at = microtime(true);
        $start = print_memory_info('cursor开始内存');
        foreach (User::where('id', '<=', '10000')->cursor() as $user) {
            //dump($user->id);
        }
        $end = print_memory_info('cursor结束内存');
        $end_at = microtime(true);

        echo '消耗内存 ',($end - $start) / 1024 .'KB','<br>';
        echo '耗时 ',$end_at - $start_at,'微妙';
}

//使用chunk方式
public function test2(Request $request)
{
        $start_at = microtime(true);
        $start = print_memory_info('Chunk开始内存');
        User::where('id', '<=', '10000')->Chunk(10000, function ($users) {
            foreach ($users as $user) {
                //dump($user->id);
            }
        });
        $end = print_memory_info('Chunk结束内存');
        $end_at = microtime(true);
        echo '消耗内存 ', ($end - $start) / 1024 .'KB', '<br>';
        echo '耗时 ', $end_at - $start_at, '微妙';
}
测试结果

firstOrNew() 和 firstOrCreate() 和firstOrUpdate()

//传参支持两种方式 两个数组或一个数组 查询和写入的数据匹配为传入的数组
$user = User::firstOrNew(['name' => 'Favian Orn'], ['email' => 'max.koss@example.com']);

firstOrnew 返回的模型还尚未保存到数据库,必须要手动调用 save 方法才能保存它
如果想使用批量赋值,需要先调用fill方法
$user->fill(['name' => '1234'])->save();

$user = User::firstOrCreate(['name' => 'Favian Orn', 'email' => 'max.koss@example.com']);
$user->update(['name' => '1234']);

$user = User::firstOrUpdate(['name' => 'Favian Orn', 'email' => 'max.koss@example.com']);