Laravel数据库迁移与数据填充


如果在开发过程中,你曾经有过手动在数据库结构中添加字段的经历,导致不同的开发者的数据库不同步,那么数据库迁移可以帮你解决这个问题。
数据库迁移就像是数据库的版本控制,可以让团队轻松修改并共享应用程序的数据库结构。迁移通常会搭配上 Laravel 的数据库结构构造器来更方便地构建数据库结构。


数据库迁移

项目的创建,环境配置等请参考laravel官方文档,此处不再赘述。

创建迁移

进入到项目根目录,执行以下命令:

php artisan make:migration create_users_table --create=users

--table 选项可用来指定数据表的名称
--create 选项指定该迁移被执行时会创建的新数据表
--path 选项会为迁移指定一个自定义路径

新的迁移文件将会被放置在 database/migrations 目录下。每个迁移文件的名称都包含了一个时间戳以 时间戳_XXX的形式命名。

迁移文件 create_users_table

打开刚才生成的迁移文件可以看到文件内容如下:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

可以看到laravel已经帮我们自动创建了updown方法:
up 方法可为数据库添加新的数据表、字段或索引。
down 方法则是用于执行回滚操作。
Schema::create接受两个参数。第一个是要创建表的表名;第二个是一个闭包(匿名函数),获取用于定义新表的 Blueprint 对象。
这里的Schema::dropIfExists('users');会判断如果存在users表会直接删除它。

  • ps: laravel会自动记录执行过的迁移,每个迁移只会执行一次。

接下来我们修改up方法,laravel的链式写法很轻松就能知道要做的操作

  public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');//主键自增ID
            $table->string('name',20)->comment('用户名');//string默认是数据库的Verchar类型,长度20,comment备注
            $table->string('email',255)->unique()->comment('邮箱');//unique添加唯一索引
            $table->string('password')->comment("密码");
            $table->rememberToken();
            $table->timestamps();//添加created_at和updated_at字段
        });
    }

执行迁移

接下来执行php artisan migrate命令来运行所有未运行过的迁移

执行迁移

生成的数据表默认字符集为utf8mb4,排序规则utf8mb4_unicode_ci
Users数据表

回滚操作

觉得表创建有问题是可以有后悔药吃的,运行以下命令即可

php artisan migrate:rollback
回滚操作

php artisan migrate:rollback命令是对上一次执行的「批量」迁移回滚,其中可能包括多个迁移文件,在 rollback 命令后加上 step 参数,可以限制回滚迁移的个数。

比如想回滚最后的 3个迁移:

php artisan migrate:rollback --step=3

回滚应用程序中的所有迁移:

php artisan migrate:reset

检查数据表或字段是否存在

重新创建users表后,突然想添加软删除功能,这时候可以创建针对users表的迁移:

php artisan make:migration change_users_table --table=users
创建迁移

编辑up方法:

public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            if (!Schema::hasColumn('users','deleted_at')) {
                $table->softDeletes();//添加软删除功能,会在users表中添加deleted_at字段
            }
        });
    }

hasColumn方法用来检查字段是否存,第一个参数是要检查的表,第二个参数是要检查的字段。
要检查users表是否存在可以使用hasTable方法。

执行php artisan migrate命令,从下图的执行结果可以看deleted_at字段已经添加进users表了

users表


数据填充

我们可以使用laravel框架的seeder类来执行数据填充,所有由框架生成的 seeders 都将被放置在 database/seeds 目录下。

php artisan make:seeder UsersTableSeeder

让我们修改UserTableSeeder下的run方法:

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class DatabaseSeeder extends Seeder
{
    /**
     * 运行数据库填充
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => str_random(10),
            'email' => str_random(10).'@gmail.com',
            'password' => bcrypt('secret'),
        ]);
    }
}

然后修改DatabaseSeeder下的run方法,在 DatabaseSeeder 类中,可以使用 call 方法执行额外的填充类,使用 call 方法允许你将数据库填充分解成多个文件。

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UserTableSeeder::class);
    }
}

执行php artisan db:seed后,数据库中就生成了一条新的用户数据。

模型工厂

有了users表,我们还可以创建一张user_card表,一位用户可以拥有多张会员卡。这时候要每张表单独填充数据就比较麻烦了,这时候就可以使用 模型工厂 来轻松地生成大量数据库记录。

首先做好准备工作,为我们的user_card创建迁移:

php artisan make:migration create_user_card_table --create=user_card

修改up方法并执行迁移:

public function up()
    {
        Schema::create('user_card', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->string('number',20)->comment('卡号');
            $table->timestamps();
            $table->softDeletes();
        });
    }

为User模型添加一对多的关系:

public function userCards()
{
    return $this->hasMany('App\UserCard');
}

接下来打开 database/factories/UserFactory.php 文件,该文件包含了一个工厂定义:

<?php

use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(App\User::class, function (Faker $faker) {
    static $password;

    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => $password ?: $password = bcrypt('secret'),
        'remember_token' => str_random(10),
    ];
});

Faker实例提供了很多可用的随机数据,比如我们要填充人名,使用$faker->name即可,它最后会生成如Prof. Shanna Jacobs这样的高度拟真数据,不需要自己再去瞎编什么test001之类的数据。unique保证了邮箱的唯一,safeEmail是防止生成真正的邮箱,用了呢个保留的那啥。。。忘了。。。

想要深入了解Faker的可以参考:https://github.com/fzaninotto/Faker

再为user_card定义一个工厂,在database/factories路径下创建UserCardFactory.php文件,因为user_card中的用户ID是关联的users表的,所以这里只需要为卡号生成一个随机数就可以了。

<?php

use Faker\Generator as Faker;

$factory->define(App\UserCard::class, function (Faker $faker) {
    return [
        'number' => random_int(10000,9999999),
    ];
});

然后我们修改UserTableSeeder下的run方法:

public function run()
{
    //模型工厂
    factory(App\User::class, 50)
        ->create()
        ->each(function ($u) {
            $u->userCards()->save(factory(App\UserCard::class)->make());
        });
}
  • factory接受两个参数:一个是Eloquent模型,另一个是批量插入的数据量。

上面run方法中的语句表示创建 50 个用户,为每个用户创建关联,并将其存到数据库中。

最后我们只需要执行命令生成数据:

php artisan db:seed

也可以指定执行一个特定的 seeder 类:

php artisan db:seed --class=UsersTableSeeder
  • PS:因为faker随机生成的名字长度会超过20,导致插入数据库时报错,解决方法:创建一个针对users表的迁移,将name的长度改为100就好了。
Schema::table('users', function (Blueprint $table) {
    if (Schema::hasColumn('users','name')) {
        $table->string('name', 20)->comment('用户名')->change();
    } 
});

现在我们可以查看数据库,会发现新增了50条关联数据。

users表
user_card表

2017-12-27

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容