【Laravel】Laravel中的数据库操作

243 阅读11分钟

weekly-calendar-outline-event-interface-symbol_icon-icons.com_73108.png 2024.04.22 | 作者:Adlerian

1.数据库的创建与配置

1.1 创建数据库

  1. 终端进入数据库bin目录

    cd D:\phpstudy_pro\Extensions\MySQL5.7.26\bin
    
  2. 使用账号登录数据库

    mysql -u root -p
    

    image-1.png

  3. 创建数据库并插入测试数据

    # ① 创建数据库,并使用USE选择数据库
    CREATE DATABASE `laravel`;
    USE `laravel`;
    # ② 在数据库中创建member数据表
    CREATE TABLE `member` (
      `id` INT PRIMARY KEY AUTO_INCREMENT,
      `name` VARCHAR(32) NOT NULL DEFAULT '',
      `age` TINYINT UNSIGNED NOT NULL DEFAULT 0,
      `email` VARCHAR(32) NOT NULL DEFAULT ''
    ) ENGINE=InnoDB CHARSET=utf8mb4;
    # ③ 在member数据表中插入测试数据
    INSERT INTO `member` VALUES (1, 'tom', 20, 'tom@laravel.test');
    

1.2 Laravel链接数据库

  1. 数据库的配置文件是config\database.php 数据库大部分配置都是通过env()函数进行加载的,我们直接修改.env文件就ok,但是在实际使用中需要在文件中写文件里面

        'mysql' => [
        'driver' => 'mysql',			// 数据库驱动
        'host' => env('DB_HOST', '127.0.0.1'),		// 主机名或IP
        'port' => env('DB_PORT', '3306'),		// 端口
        'database' => env('DB_DATABASE', 'forge'),	// 数据库名
        'username' => env('DB_USERNAME', 'forge'),	// 用户名
        'password' => env('DB_PASSWORD', ''),		// 密码
        'unix_socket' => env('DB_SOCKET', ''),		// socket路径
        'charset' => 'utf8mb4',			// 字符集
        'collation' => 'utf8mb4_unicode_ci',		// 校对集
        'prefix' => '',			// 数据库表前缀
        'strict' => true,			// 使用严格模式
        'engine' => null,			// 指定存储引擎
    ],
    
  2. .env文件里面找到数据库配置,对配置进行修改

    DB_CONNECTION=mysql   # 数据库
    DB_HOST=127.0.0.1     # 链接地址
    DB_PORT=3306          # 端口
    DB_DATABASE=laravel   # 数据库名
    DB_USERNAME=root      # 用户名
    DB_PASSWORD=123456    # 密码
    

2. 使用DB类操作数据库

Laravel中,DB类对常用的数据库操作进行了封装,可以完成数据的添加、修改、查询和删除等操作,对于一些复杂的需求,也可以手写SQL让DB类执行

2.1 DB类的使用步骤

  1. 在控制器引入 DB

    //TestController
    <?php
    ......
    
    use DB;  //引入
    ....
    
  2. 在TestController中编写一个database()方法,用于测试DB类

    public function database()
    {
    $data = DB::table('member')->get();
    foreach ($data as $v) {
        dump($v->id . '-' . $v->name);
        }
    }
    
  3. 将database()方法添加到路由

    Route::get('test/database', 'TestController@database');
    
  4. 通过浏览器访问

    成功查询到Member数据

    image-3.png

2.2 添加数据

使用DB类为数据表添加数据有两个常用的方法,分别是insert()和insertGetId()

insert()方法:返回值为 true 或 false,表示是否添加成功

insertGetId()方法:返回值为自动增长的 id

  1. 单条数据添加

    $data = [
        'name' => 'and',
        'age' => '22',
        'email' => 'tom@laravel.test'
    ];
    // insert()方法
    dump(DB::table('member')->insert($data));
    // insertGetId()方法
    dump(DB::table('member')->insertGetId($data));
    

    image.png

  2. 使用insert( )方法还可以同时添加多条数据

    $data = [
        ['name' => 'tom', 'age' => '23', 'email' => 'tom@laravel.test'],
        ['name' => 'jim', 'age' => '24', 'email' => 'jim@laravel.test'],
        ['name' => 'tim', 'age' => '25', 'email' => 'tim@laravel.test'],
    ];
    // insert()方法
    dump(DB::table('member')->insert($data));
    

2.3 修改数据

  1. 修改数据可以用update()、increment()或decrement()方法来实现,这些方法的返回值是受影响的行数。

    • update()方法用于修改指定的字段;
    • increment()方法用于对数字进行递增;
    • decrement()方法用于对数字进行递减。
    // 将表中所有记录的name字段的值都改为tom
    $data = ['name' => 'tom'];
    dump(DB::table('member')->update($data));
    // 将表中所有记录的age字段的值都加1
    dump(DB::table('member')->increment('age'));
    // 将表中所有记录的age字段的值都减1
    dump(DB::table('member')->decrement('age'));
    // 将表中所有记录的age字段的值都加5
    dump(DB::table('member')->increment('age', 5));
    //将表中所有记录的age字段的值都减5
    dump(DB::table('member')->decrement('age', 5));
    
  2. 实际开发中,通常会用WHERE条件限定要操作的记录。因此,在调用update()、increment()或decrement()方法前,可以先调用where()方法传递一些WHERE条件

    $data = [
            // 添加单条数据
            'name' => 'adler',
            'age' => '66',
            'email' => 'adler@laravel.test'
        ];
        // 参数形式1:where(字段名, 运算符, 字段值)
        DB::table('member')->where('id', '=', '1')->update($data);
        // 参数形式2:where(字段名, 字段值),使用“=”运算符
        DB::table('member')->where('id', '1')->update($data);
        // 参数形式3:where([字段名 => 字段值]),使用“=”运算符,支持多个字段,AND关系
        DB::table('member')->where(['id' => 1])->update($data);
    
  3. 有多个 WHERE 条件时:

    在 where()的后面连续调用 where()表示 AND 条件

    在 where()的后面连续调用 orWhere()表示 OR 条件

    $data = [
            // 添加单条数据
            'name' => 'adler',
            'age' => '66',
            'email' => 'adler@laravel.test'
        ];
        // where()表示AND,即 “WHERE id=1 AND name='tom'”
        DB::table('member')->where(['id' => 6])->where(['name' => 'tom'])->update($data);
        // orWhere()表示OR,即“WHERE id=1 OR name='tom'”
        DB::table('member')->where(['id' => 1])->orWhere(['name' => 'tom'])->update($data);
    

    image-7.png

    image.png

  4. where()和orWhere()方法也可以用于查询数据、删除数据的操作中。

2.4 查询数据

  1. 查询多行数据

    使用get()方法获取多行数据,返回值是集合(Collection),通过foreach取出里面的每一条记录。

    由于每一条记录都是一个对象,需要用对象访问属性的方式来获取指定字段的值。

    //查询全部
    $data = DB::table('member')->get();
    foreach ($data as $v) {
        echo $v->id . '-' . $v->name . '<br>';
    }
    // 指定查询条件
    DB::table('member')->where('id', '<', 3)->get();
    foreach ($data as $v) {
            echo $v->id . '-' . $v->name . '<br>';
    }
    

    image.png

  2. 查询单行数据

    使用first()方法获取单行数据,返回值是对象,通过访问对象的属性来获取字段的值。

    // 查询id为1的记录
    $data = DB::table('member')->where('id', '1')->first();
    // 输出id字段的值
    dump($data->id);
    

    image.png

  3. 查询指定字段的值

    调用get()、first()方法时通过数组参数传入要查询的字段。

    // 获取name和email两个字段,返回多条记录
    $data = DB::table('member')->get(['name', 'email']);
    dump($data);
    

    image.png

     // 获取name和email两个字段,返回一条记录
    $data = DB::table('member')->first(['name', 'email']);
    dump($data);
    

    image.png

    使用select()方法指定要查询的字段。

    // 获取name、email两个字段
    $data = DB::table('member')->select('name', 'email')->get();
    dump($data);
    

    image.png

    // 获取name、email两个字段(数组参数)
    $data = DB::table('member')->select(['name', 'email'])->get();
    dump($data);
    

    image.png

     // 获取name字段,并设置别名为username
    $data = DB::table('member')->select('name as username')->get();
    dump($data);
    

    image.png

     // 不解析字段,直接传入字符串作为字段列表
    $data = DB::table('member')->select(DB::raw('name,age'))->get();
    dump($data);
    

    image.png

  4. 查询某个字段的值 使用value()方法返回某个字段的值,该方法的参数是字段名,返回结果是该字段的值。

    // 查询id为1的记录,返回name字段的值
    $name = DB::table('member')->where('id', '1')->value('name');
    // 输出结果
    dump($name);
    

    image.png

  5. 排序 使用orderBy()方法进行排序,第1个参数指定排序字段,第2个参数指定排序规则,包括asc(升序)或desc(降序)。

    $data = DB::table('member')->orderBy('age', 'desc')->get();
    dump($data);
    

    image.png

  6. 分页 使用limit()方法和offset()方法实现分页,limit()方法指定每页显示的记录数,offset()方法设置开始的偏移量。

    $data = DB::table('member')->limit(3)->offset(2)->get();
    dump($data);
    

    limit(3)和 offset(2)相当于 SQL 语句中的“LIMIT 3, 2”。

    image.png

2.5 删除数据

  1. 使用delete()方法删除指定的记录,返回值为删除的行数
    // 删除id为1的记录,返回值为删除的行数
    $res = DB::table('member')->where('id', '1')->delete();
    dump($res);
    
  2. 使用truncate()方法清空整个数据表,相当于SQL中的“TRUNCATE member”
    // 清空数据表(相当于SQL中的“TRUNCATE member”)
    DB::table('member')->truncate();
    

2.6 执行SQL

通过DB类直接执行SQL语句:

// 执行SELECT语句,返回结果集
$data = DB::select('SELECT * FROM `member`');
dump($data);
// 执行INSERT语句,返回true或false
DB::insert('INSERT INTO `member` SET `name`=\'tom\'');
// 执行UPDATE语句,返回受影响的行数
DB::update('UPDATE `member` SET `age`=\'20\' WHERE `name`=\'tom\'');
// 执行DELETE语句,返回受影响的行数
DB::delete('DELETE FROM `member` WHERE `name`=\'tom\'');
// 执行其他语句,如CREATE TABLE,返回true或false
DB::statement('CREATE TABLE `test` (`id` INT)');

2.7 链接查询

步骤:

  • 创建文章表和作者表,每一篇文章都有一个作者,在文章表中需要保存作者的 id。
  • 编写 SQL 语句查询文章,把文章的作者也查询出来。

创建文章表和作者表的 SQL 语句:

# 文章表
CREATE TABLE `article` (
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `article_name` VARCHAR(50) NOT NULL COMMENT '文章名称',
  `author_id` INT UNSIGNED NOT NULL COMMENT '作者id'
) DEFAULT CHARSET=utf8mb4;
# 作者表
CREATE TABLE `author` (
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `author_name` VARCHAR(20) NOT NULL COMMENT '作者名称'
) DEFAULT CHARSET=utf8mb4;
# 测试数据
INSERT INTO `article` VALUES (1, '欢迎使用Laravel', 1);
INSERT INTO `author` VALUES (1, '张三');

image.png

链接查询

SELECT t1.`id`, t1.`article_name`, t2.`author_name`
FROM `article` AS t1
LEFT JOIN `author` AS t2
ON t1.`author_id`=t2.`id`;

image.png

在控制器中多表查询‘

$data = DB::table('article AS t1')->select(
            't1.id',
            't1.article_name AS article_name',
            't2.author_name AS author_name'
        )->leftjoin(
                'author AS t2',
                't1.author_id',
                '=',
                't2.id'
            )->get();
        foreach ($data as $v) {
            echo $v->id . '-' . $v->article_name . '-' . $v->author_name;
        }

image.png

3.使用模型操作数据库

3.1 初识模型

Laravel 内置了 Eloquent 模型组件,使用该组件操作数据库。Eloquent 模型采用对象关系映射(Object Relational Mapping,ORM)的设计思想。

ORM:用来在关系型数据库和对象之间做一个映射,它将数据库中的表作为类,表中的记录作为对象,表中的字段作为属性,使用 ORM 操作数据库和操作对象类似

  • 普通查询和使用 Eloquent 模型查询的区别:
    // 普通查询方式
    $sql = 'SELECT id,name FROM member WHERE id = 1';
    $data = DB::select($sql);
    $username = $data[0]->name;
    // Eloquent模型查询
    $member = Member::find(1);
    $username = $member->name;
    
  • 使用 Eloquent 模型操作数据库的优点:
    1. 不需要书写 SQL 语句,直接使用已经封装好的数据库操作就可以查询数据。
    2. 数据模型都统一定义,容易更新和维护,也利于代码重用。
    3. ORM 有封装好的工具,很多功能都可以自动完成,比如预处理、事务等。
    4. 业务代码比较简单,代码量少,语义性好,容易理解。

3.2 定义模型

定义模型的命令:

php artisan make:model 模型名

新增模型

image.png

image.png

在模型中指定表名:Laravel 自动将 Member 模型名转换为表名,并使用复数形式,即 members。也可以在模型中使用$table 属性来指定表名。

class Member extends Model
{
    protected $table = 'member';
}

模型类中的其他可选属性:

  • protected $primaryKey:设置主键的名称,默认值为 id,如果主键名称有误,会导致程序出错。
  • public $timestamps:是否自动维护时间戳,默认为 true。设为 true 时,模型会自动维护表中的 created_at(创建时间)和 updated_at(更新时间)字段。
  • protected $fillable:允许某些字段可以被添加或修改,格式为一维数组形式。使用模型的create()方法添加数据时,需要设置$fillable。
  • protected $guarded:禁止某些字段被添加或修改,与$fillable 只能二选一。

public $timestamps是默认开启的,因此需要为数据表添加created_at和updated_at字段

image.png

关闭自动维护时间戳

public $timestamps = false;

3.3 使用模型

在控制器文件中引入模型的命名空间:

use App\Member;

添加上述代码后,就可以通过 Member 类来使用模型了。

模型的使用方式:

  • 静态调用
  • 实例化模型
// 方式1:静态调用
Member::get();
// 方式2:实例化模型
$member = new Member();
$member->get();

3.4 模型添加数据

image.png

  1. save()方法

    使用方式:先实例化模型,为模型的属性赋值,模型的属性对应数据表的字段,赋值完成后调用 save()方法保存。

     $member=new Member();
     $member->name = 'server';
     $member->age='21';
     $member->email = 'server@laraver.net';
     dump($member->save());
     dump($member->id);
    
  2. fill()方法

    以数组的方式填充数据,数组的键名对应字段名,填充后调用 save()方法保存。

    $data = ['name' => 'fill', 'age' => '20', 'email' => 'fill@laravel.test'];
    $member = new Member();
    $member->fill($data);
    $member->save();
    
  3. create()方法

    在实例化模型的同时为模型填充数据,调用 save()方法保存。

    $data = ['name' => 'tom', 'age' => '20'];
    $member = Member::create($data);
    $member->save();
    

    image.png

3.5 模型查询数据

image.png

  1. find()方法

    根据主键查询记录,如果数据不存在返回 null

    // 查询主键为4的记录,返回模型对象
    $member = Member::find(4);
    dump($member->name);		// 获取name字段的值
    // 添加查询条件,返回name和age字段
    $member = Member::where('name', 'tom')->select('name', 'age')->find(1);
    dump($member);
    // 查询主键为1、2、3的记录,返回对象集合
    $members = Member::find([1, 2, 3]);
    dump($members);
    
  2. get()方法

    与 DB 类的 get()方法类似,两者的返回结果都是对象集合,但对象的类型不同。

    模型的 get()方法返回的是模型对象的集合。

    DB 类的 get()方法返回的是普通对象的集合。

    // 模型的get()方法
    $members = Member::where('id', '1')->get();
    dump(get_class($members[0]));    // 输出结果:"App\Member"
    // DB类的get()方法
    $members = DB::table('member')->where('id', 1)->get();
    dump(get_class($members[0]));    // 输出结果:"stdClass"
    

    image.png

  3. all()方法

    查询表中所有的记录,返回模型对象集合,all()方法前不能调用 where()、select()方法。

    // 查询所有记录,返回对象集合
    $members = Member::all();
    dump($members);
    

    image.png

     // 查询所有记录的name和age字段,返回对象集合
    $members = Member::all(['name', 'age']);
    dump($members);
    

    image.png

3.6 模型修改数据

使用模型修改数据的两种方式:

  • 先查询后保存,通常用于在保存前进行一些操作。
  • 直接修改
// 用模型进行数据查询
// 方式1:先查询后保存
$member = Member::find(3);
if ($member) {
   $member->name = 'test1';
   $member->email = 'test1@laravel.test';
   $member->save();
   dump('修改成功');
} else {
   dump('修改失败:记录不存在');
}
// 方式2:直接修改
 Member::where('id', 6)->update(['name' => 'test2', 'age' => 30]);

3.7 模型删除数据

// 先查询后删除数据
$member = Member::find(4);
if ($member) {
    $member->delete();
    dump('成功');
 } else {
     dump('修改失败');
 }
//直接删除
Member::where('id', 5)->delete();
dump($data);

4.关联模型的使用

4.1 一对一

image.png

4.2 一对多

一位作者可以发表多篇文章,作者和文章就是一对多的关系。

在Author模型建立一对多关联:使用hasMany()方法建立一对多关系

public function article()
{
    return $this->hasMany('App\Article', 'author_id', 'id');
}

在TestController的test()方法中查询数据:

public function test()
{
    $data = \App\Author::all();
    foreach ($data as $key => $value) {
        echo '作者名称:' . $value->author_name . '<br>';
        foreach ($value->article as $k => $v) {
            echo $v->article_name . '<br>';
        }
    }
}

4.3 多对一

将一对多的关系反过来,就是多对一的关系,使用belongsTo()方法建立多对一关系。

修改Article模型的author()方法,建立多对一关联:

public function author()
{
    return $this->belongsTo('App\Author', 'author_id', 'id');
}

在TestController的test()方法中查询数据:

public function test()
{
    $data = \App\Article::all();
    foreach ($data as $key => $value) {
        echo '文章id:' . $value->id . '<br>';
        echo '文章名称:' . $value->article_name . '<br>';
        echo '作者名称:' . $value->author->author_name;
    }
}

4.4 多对多

一篇文章有多个关键词,一个关键词可以被多个文章使用,那么文章和关键词就是多对多的关系。

多对多可以拆分成两个一对多关系,两个一对多关系需要借助第3张表(中间表)来建立关系。

创建关键词表和中间表:

# 创建关键词表
CREATE TABLE `keyword` (
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `keyword` VARCHAR(255) NOT NULL COMMENT '关键词'
) DEFAULT CHARSET=utf8mb4;
# 创建中间表,保存文章和关键词的关联
CREATE TABLE `article_keyword` (
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `article_id` INT UNSIGNED NOT NULL COMMENT '文章id',
  `keyword_id` INT UNSIGNED NOT NULL COMMENT '关键词id'
) DEFAULT CHARSET=utf8mb4;

1. 使用文章模型查询关键字

在文章模型中使用belongsToMany()方法建立多对多关联。

public function keyword()
{
    return $this->belongsToMany(
        'App\Keyword',
        'article_keyword',
        'article_id', 
        'keyword_id'
    );
}
  • 第1个参数表示被关联模型的命名空间。
  • 第2个参数表示中间表的表名。
  • 第3个参数表示中间表中当前模型的关系字段。
  • 第4个参数表示中间表中被关联模型的关系字段。

在TestController的test()方法中查询数据:

public function test()
{
    $data = \App\Article::all();
    foreach ($data as $key => $value) {
        echo '文章名称:' . $value->article_name . '<br>';
        echo '关键词:';
        foreach ($value->keyword as $k => $v) {
            echo $v->keyword . ' ';
        }
        echo '<hr>';
    }
}

2. 使用关键字查询数据

在关键词模型中建立多对多关联:

public function article()
{
    return $this->belongsToMany('App\Article', 'article_keyword',
    'keyword_id', 'article_id');
}

在TestController的test()方法中查询数据:

public function test()
{
    $data = \App\Keyword::all();
    foreach ($data as $key => $value) {
        echo '关键词:' . $value->keyword . '<br>';
        echo '相关文章:';
        foreach ($value->article as $k => $v) {
            echo $v->article_name . ' ';
        }
        echo '<hr>';
    }
}

5.数据表的迁移和填充

5.1 数据表迁移

数据表迁移共分为两步:

  • 第1步是创建迁移文件,

  • 第2步是执行迁移文件。

迁移文件的保存目录为database\migrations,命名方式为“时间版本_create_表名_table.php”。

  1. 创建迁移文件

    创建迁移文件命令:

    php artisan make:migration 迁移文件名
    

    创建paper表迁移文件命令:

    php artisan make:migration create_paper_table
    

    paper表对应的迁移文件部分示例代码:

    public function up()
     {
            Schema::create('paper', function (Blueprint $table) {
                $table->increments('id');
                $table->timestamps();
            });
    }
    function down()
    {
            Schema::dropIfExists('paper');
    }
    

    paper表的字段要求:

    • id:表的主键,自动增长。
    • paper_name:试卷名称,VARCHAR(100)类型,不允许重复值。
    • total_score:试卷总分,TINYINT类似,默认为0。
    • start_time:试卷开始考试时间,INT类型(保存时间戳)。
    • duration:考试时间长度,单位为分钟,TINYINT类型。
    • status:试卷是否启用,TINYINT类型,1表示启用,2表示禁用,默认为1。
    • created_at:创建时间,TIMESTAMP类型,默认为NULL。
    • updated_at:更新时间,TIMESTAMP类型,默认为NULL。

    paper表字段对应的迁移代码:

    Schema::create('paper', function (Blueprint $table) {
        $table->increments('id')->comment('主键');
        $table->string('paper_name', 100)->comment('试卷名称')->unique();
        $table->tinyInteger('total_score')->default(0)->comment('试卷总分');
        $table->integer('start_time')->comment('考试开始时间');
        $table->tinyInteger('duration')->comment('考试时长');
        $table->tinyInteger('status')->default(1)->comment('状态');
        $table->timestamps();
    });
    
  2. 执行迁移文件

    在项目中第一次执行迁移文件时,需要安装迁移,安装迁移命令:

    php artisan migrate:install
    

    安装迁移后,生成migrations表保存迁移记录,migrations表字段:

    • id:表的主键,用来唯一标识每条记录。
    • migration:用来记录执行过的迁移文件。
    • batch:用来记录批次,每次执行迁移命令,批次就会加1。如果在一次迁移命令中迁移了两张表,那么这两张表就属于同一个批次。

    执行迁移命令:

    php artisan migrate
    

    回滚迁移命令:

    php artisan migrate:rollback
    

5.2 数据库填充

  1. 创建填充文件

    填充文件又称为填充器、种子文件,创建命令:

    php artisan make:seeder 填充器名称
    

    创建paper表填充文件:

    php artisan make:seeder PaperTableSeeder
    

    PaperTableSeeder.php填充文件部分示例代码:

    <?php
    
    use Illuminate\Database\Seeder;
    
    class PaperTableSeeder extends Seeder
    {
        public function run()
        {
            //
        }
    }
    

    在run()方法中编写填充代码:

    public function run()
    {
        DB::table('paper')->insert([
            [
                'paper_name' => 'PHP期末复习题',
                'total_score' => 100,
                'start_time' => time() + 86400,
                'duration' => 120,
                'status' => 1
            ],
            ……(添加更多数据)
        ]);
    }
    
  2. 执行填充文件

    执行PaperTableSeeder.php填充文件的命令:

    php artisan db:seed --class=PaperTableSeeder
    

END | DigitalSpring

DigitalSpring Blog by Adlerian is licensed under CC BY-NC-ND 4.0