laravel5.8之模型操作数据库 — Eloquent ORM(实践)

阐述

Laravel操作数据库有三种方式:

一种是用DB类操作原生sql。
一种是用构造器查询。
一种是Laravel里独特的模型操作方式,即Eloquent ORM。

准备工作

1. 配置数据库信息(已配置好的自动忽略)

操作前,找到根目录下的 .env文件,配置好数据库连接信息。

2. 配置模型管理

为了方便文件统一管理,我们统一把模型文件放在 /app/Models/ 文件夹下。

注意:因为 laravel5.8 默认在 app 文件夹下有一个的 User 模型文件,如果有需要,可以再重新生成一个 User 模型文件在 Models 中,再更改一下 /config/auth.php下的配置,更改如下:

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,    // 此处更改为App\Models\User
    ],

    // 'users' => [
    //     'driver' => 'database',
    //     'table' => 'users',
    // ],
],

3. 生成模型文件

Windows系统下进入dos系统,跳转到项目根目录(linux直接跳转),执行以下命令在Models中生成一个 User.php 模型文件:

php artisan make:model Models\User

执行后的结果:

在这里插入图片描述

4. 设置模型文件中的代码

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
    
    
	// 为模型指定表名
    protected $table         = 'users';		  
    // 默认情况下指定'id'作为表主键,也可以指定主键名             
    protected $primaryKey    = 'id';	  
    // 默认情况下,Eloquent 期望数据表中存在 created_at 和 updated_at 字段,设置false可以取消。                      
    protected $timestamps    = true; 	   
     // 定制时间戳的格式                     
    protected $dateFormat    = 'U'; 	
    // 定义允许添加、更新的字段白名单,不设置则无法添加数据                       
    protected $fillable      = ['name', 'sex', 'age','pwd'];   
    // 定义不允许更新的字段黑名单 
    protected $guarded       = ['id']; 			        
}

注意: 一般开发时,以上属性配置 $fillable 就行,如果有特殊需要,再配置其他属性就好。

操作模型进行数据库操作

1. 使用 artisan 工具创建 user 控制器,如下命令:

php artisan make:controller Home/UserController

/app/Http/controllers/Home/ 文件夹下生成 UserController.php
在这里插入图片描述
控制器打开有如下自动生成的代码:

<?php
 
namespace App\Http\Controllers\Home;
 
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
 
class UserController extends Controller
{
    
    
    //
}

2. 引入模型类

use App\Models\User;

3. 使用 save方法 添加一条数据

public function insert(Request $request)
{
    
    
    // 获取数据
    $data = $request->validate([
        'name'  =>  'required',
        'pwd'   =>  'required',
        'sex'   =>  'required',
        'age'   =>  'required'
    ]);
    
    // 实例化模型
    $user = new User;
    $user->name = $data['name'];
    $user->pwd  = $data['pwd'];
    $user->sex  = $data['sex'];
    $user->age  = $data['age'];
    
    // 向数据库中插入一条记录,返回值为新增数据数组对象
    $result = $user->save();  // 返回真假
}

4. 使用 create方法 添加一条数据

public function insert(Request $request)
{
    
    
    // 获取数据
    $data = $request->validate([
        'name'  =>  'required',
        'pwd'   =>  'required',
        'sex'   =>  'required',
        'age'   =>  'required'
    ]);
    // 向数据库中插入一条记录,返回值为新增数据数组对象
    return User::create($data);
 
    // 先判断当前插入数据是否存在,存在则查找存在的第一条数据返回,不存在则执行插入,返回新增
    return User::firstOrCreate($data);
}

PS:如果要批量添加数据,可以使用 DB 操作,如:

DB::table('users')->insert([
    ['name'=>'test1', 'pwd'=>'123', 'sex'=>1, 'age'=>1],
    ['name'=>'test1', 'pwd'=>'123', 'sex'=>1, 'age'=>1],
    ['name'=>'test1', 'pwd'=>'123', 'sex'=>1, 'age'=>1],
    ['name'=>'test1', 'pwd'=>'123', 'sex'=>1, 'age'=>1]
]);

注意:使用 DB 操作时,需要先引入 —— use DB;

5. save 更新单条数据

public function update(Request $request)
{
    
    
    $data = $request->validate([
        'id' => 'required'
    ]);
 
    // 更新数据前需要先获取当前数据
    $user = User::find($data['id']);
 
    // 获取和设置要进行更新的数据
    $map = $request->except('id');
 
    if (empty($map)) {
    
    
        return '没有更新任何数据';
    }
 
    foreach ($map as $k => $v) {
    
    
        $user->$k = $v;
    }
 
    // 返回更新后的用户信息集合
    $result = $user->save();
}

6. update 更新指定 ID 条件的单条数据

public function update()
{
    
    
    User::where('id', 1)->update(['name' => 'update_name']);
}

7. update 限定 where 约束条件批量更新数据

public function updateWhere()
{
    
    
    User::where('sex', 2)->where('age','>',30)->update([
        'name' => 'update_name'
    ]);
}

8. 删除数据

public function delete(Request $request)
{
    
    
    // 删除指定id的数据
    $id = $request->input('id');
    $user = User::find($id);
    $user->delete(); 
 
    // destroy删除指定的单个或多个id的数据
    User::destroy(1);            //删除主键为1的记录
    User::destroy([1, 2, 3]);    //删除主键为1,2,3的记录
 
    // 根据条件批量删除数据
    $deletedRows = User::where('age', 445)->delete();
}

9. 查询所有数据

public function all()
{
    
    
    return User::all();
}

10. 查询指定ID的数据

public function find($id)
{
    
    
    // 普通查询
    return User::find($id);
 
    // 使用下面的查询方法未查到数据,则会抛出404错误
    return User::findOrFail($id);
}

11. 指定条件查询数据

public function findwhere() 
{
    
    
    // 指定条件查询第一条数据,返回一维数组对象
    return User::where(['sex'=>1, 'age'=>'21'])->first();
 
    //根据where查询符合条件第一条记录,没有则抛出404
    return User::where('age', '>', 21)->firstOrFail();
 
    // 指定条件查询全部数据,返回二维数组对象
    return User::where(['sex'=>1, 'age'=>'21'])->get();
}

12. 按照指定排序方式查询数据

public function findOrderBy() 
{
    
    
    // 按照创建时间排序,返回第一条用户数据
    return User::orderBy('created_at', 'desc')->first();
}

13. 组合查询(获取前几条数据)

public function findWhere()
{
    
    
     return User::where('age','>',10)    // 年龄大于10
                ->where(['sex'=>1])      // 性别为男
                ->orderBy('age', 'desc') // 按照年龄大小逆向排序
                ->take(5)                // 获取前面5条数据
                ->get();
}

14. 统计查询

public function count()
{
    
    
    // 根据条件统计数量
    return User::where('sex', 1)->count();
 
    // 获取满足条件的最大年龄
    return User::where('sex', 1)->max('age');
}

15. 分页查询

/*
 *    获取数据分页
 *
 *    参数:
 *        1. $num :每页显示数量;
 *        2. $colum :查询指定字段;
 *        3. $pageName :分页名称,即上下页链接分页参数名称;
 *        4. $p :指定获取的页数   
 */
public function paginate($num = 10, $colum = [*], $pageName = 'page', $p = 1)
{
    
    
    return User::where('sex', 1)->orderBy('created_at', 'desc')->paginate($num, $colum, $pageName, $p);
}
 
 
// 返回数据样式
{
    
    
   "total": 50,                                    // 数据总数量
   "per_page": 15,                                 // 每页显示数量
   "current_page": 1,                              // 当前页码
   "last_page": 4,                                 // 上一页码
   "first_page_url": "http://laravel.app?page=1",  // 首页链接
   "last_page_url": "http://laravel.app?page=4",   // 最后页链接
   "next_page_url": "http://laravel.app?page=2",   // 下一页链接
   "prev_page_url": null,                          // 上一页链接
   "path": "http://laravel.app",                   // 根地址
   "from": 1,                                      // 当前页数据来源页
   "to": 10,                                       // 当前页数据量
   "data":[                                        // 当前页数据数组
        {
    
    
            // Result Object
        },
        {
    
    
            // Result Object
        }
   ]
}

16. 分块查询

问题背景:

一个完整的项目经常会隔一段时间收集、处理大批量的数据,常常是对一整张表的数据处理,而我们直接的思路往往是直接获取所有数据,然后遍历每一条数据进行操作。

如果数据量很小,这样处理没问题,但如果数据量很大(一般超过5K就算大批量数据了),每一次遍历进行的数据更新操作又多,那很有可能会遇到代码执行超时的问题,并且循环几万、几十万的数据操作时,很有可能会把服务器运行内存消耗完,那就直接 down 机了,更恐怖。

解决思路:

每次获取一段数据块再进行遍历操作,当前数据块儿处理完成,再获取第二部分数据块儿。这样每次循环都是一小块儿数据,一个块儿数据遍历结束后再重新获取数据进行遍历,就解决了上面的问题。

(1)普通数据遍历和块查询遍历处理的区别代码演示

// 普通代码演示
$users = User::all();
foreach ($users as $user) {
    
    
  $user->update(['sex' => 1]);
}
 
// 按每次处理100条数据块的方式优化代码演示
User::chunk(100, function ($users) {
    
    
  foreach ($users as $user) {
    
    
    $user->update(['sex' => 1]);
  }
});

(2)带条件的块查询遍历处理

User::where('age', '>', '20')->chunk(100, function ($users) {
    
    
  foreach ($users as $user) {
    
    
    $user->update(['sex' => 1]);
  }
});

注意:如果是 “自更新” 的块查询处理,则会漏掉一半的数据,如下演示:

User::where('sex', 0)->chunk(100, function ($users) {
    
    
  foreach ($users as $user) {
    
    
    $user->update(['sex' => 1]);
  }
});

说明:

运行上面的代码,不会报错,执行的逻辑是找出性别未知(sex=0)的用户,一次操作100位未知性别用户,修改性别字段 sex=1。

逻辑很简单,但在这个过程中,当第一个数据库的数据被修改后,下一个数据块的数据将是在被修改后的数据中选出来的,这个时候数据变了,而 page 也加了 1,所以执行结束后,只对数据中一半的数据进行了更新操作。

如果没有明白的话,来看一下 chunk 的底层实现。

还以上面的代码为例,假如一共有 400 条数据,数据被按照 100 条进行分块处理。

page = 1:最开始的时候 page 为 1,选取 1-100 条数据进行处理;

page = 2:这时候前一百数据的 sex 值全部为1,那么再次筛选的时候数据将从第101条开始(此时 sex=0 筛选出来的是除改修改后的剩下300条),如果此时 page 仍然等于1,则可以按照我们正常需求执行,但这个时候的 page=2,那么处理的数据将是第200-300之间的数据。

chunk 函数如下:

public function chunk($count, callable $callback)
{
    
    
    $results = $this->forPage($page = 1, $count)->get();
 
    while (count($results) > 0) {
    
    
        // On each chunk result set, we will pass them to the callback and then let the
        // developer take care of everything within the callback, which allows us to
        // keep the memory low for spinning through large result sets for working.
        if (call_user_func($callback, $results) === false) {
    
    
            return false;
        }
 
        $page++;
 
        $results = $this->forPage($page, $count)->get();
    }
 
    return true;
}

17. 软删除

软删除并不是物理删除,只是在对应表中添加字段 "delete_at",在使用模型查找数据时,自动判断 delete_at 是否为空,如果不为空则判断为已被软删除,反之则说明未被删除。先执行以下配置:

(1) 要使用软删除的模型能力,需要先在模型文件中引入软删除引擎,此处配置 User 模型作为参考:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;    // 引入软删除引擎
 
class User extends Model
{
    
    
    use SoftDeletes;                             // 调用软删除类
 
    protected $dates = ['deleted_at'];
 
    protected $fillable = [
        'name', 'email', 'password', 'image'
    ];
}

(2)使用迁移增加 delete_at 字段

php artisan make:migration alter_users_table --table=users

(3)填充迁移文件

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

(4)执行迁移文件

php artisan migrate

(1)判断某条数据是否已被软删除

配置以上,则可以进行软删除相关操作,具体如下:

$user = User::find(1);
 
if ($user->trashed()) {
    
        // 判断是否被软删除
      
}
(2)强制查询所有数据(包括被软删除的数据)
User::withTrashed()->where('sex', 1)->get();

(3)只查询被软删除的数据

User::onlyTrashed()->where('sex', 1)->get();

(4)恢复被软删除的数据

$user = User::find(1);
$user->restore();

(5)批量恢复多个被软删除的数据

User::withTrashed()->where('sex', 1)->restore();

(6)强制删除指定数据

$user = User::find(1);
 
// 强制删除单个模型实例...
$user->forceDelete();
 
// 强制删除所有相关模型...
$user->history()->forceDelete();

猜你喜欢

转载自blog.csdn.net/weiguang102/article/details/125723143