Laravel 中數(shù)據(jù)遷移和數(shù)據(jù)填充

image

本文首發(fā)于 https://jaychen.cc
作者 JayChen

這是一篇基礎(chǔ)教程淋淀,對標(biāo) Laravel 文檔中的數(shù)據(jù)遷移數(shù)據(jù)填充袒炉。

migration

Laravel 中提供了數(shù)據(jù)庫遷移的方式來管理數(shù)據(jù)庫冶共,想象一個(gè)場景:在一個(gè)多人開發(fā)的項(xiàng)目中,你的同事修改了某個(gè)數(shù)據(jù)庫結(jié)構(gòu)并修改了代碼抡锈,通過 git 你可以即時(shí)的同步同事修改的代碼渡紫,但是數(shù)據(jù)庫結(jié)構(gòu),你只能通過手工的方式來復(fù)制同事修改的 SQL 語句凤粗,執(zhí)行以保證數(shù)據(jù)庫的結(jié)構(gòu)一致酥泛。那么,Laravel 中的數(shù)據(jù)庫遷移概念嫌拣,就是用于解決團(tuán)隊(duì)中保證數(shù)據(jù)庫結(jié)構(gòu)一致的方案柔袁。

migration 使用非常簡單,編寫一定的 php 代碼并執(zhí)行亭罪,那么 Laravel 就會(huì)自動(dòng)的更新數(shù)據(jù)庫瘦馍。假設(shè)你的同事要修改數(shù)據(jù)庫某個(gè)字段,那么只要編寫 php 代碼应役,接著你通過 git 更新了代碼情组,執(zhí)行 migrate 操作之后燥筷,你的數(shù)據(jù)庫結(jié)構(gòu)就和他的同步了。下面我們就來看具體的使用方法院崇。

migrate

Laravel 把編寫數(shù)據(jù)庫改動(dòng)的 php 代碼稱為遷移肆氓,可以通過 php artisan make:migration filename 的方式來創(chuàng)建遷移文件。假設(shè)你需要?jiǎng)?chuàng)建一張新的 user 表底瓣,那么你可以通過執(zhí)行 php artisan make:migration create_user_table --create=user 來創(chuàng)建一個(gè)遷移文件谢揪,執(zhí)行命令會(huì)在 database/migrations/ 目錄下建立一個(gè) 文件創(chuàng)建時(shí)間_filename 的 php 文件,那么這個(gè)文件就是我們接下來用來編寫數(shù)據(jù)庫結(jié)構(gòu)變化的文件了捐凭。這里要提一點(diǎn)拨扶,雖然說創(chuàng)建遷移文件的名稱可以隨意,但是為了管理方便茁肠,最好文件名可以體現(xiàn)要執(zhí)行的數(shù)據(jù)庫操作患民,比如這里我們要?jiǎng)?chuàng)建一張 user 表,所以文件名稱為 create_user_table垦梆。

php artisan make:migration filename 有兩個(gè)可選參數(shù)

  • --create=tablename 表明該遷移是用來創(chuàng)建表匹颤。
  • --table=tablename 表明該遷移是用來對 tablename 這張表進(jìn)行操作。

我們創(chuàng)建出來的遷移文件 create_user_table 會(huì)包含兩個(gè)方法托猩。


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


public function down()
{
    Schema::dropIfExists('user');
}

這兩個(gè)方法是互逆的操作印蓖,比如我們可以再 up 方法中編寫我們要?jiǎng)?chuàng)建的 user 表的相關(guān)信息,而 down 方法中則是刪除 user 表的操作京腥。這樣赦肃,我們就可以做到回滾操作,當(dāng)我們創(chuàng)建 user 表之后發(fā)現(xiàn)某個(gè)字段名寫錯(cuò)了绞旅,就可以通過 down 來刪除 user 表摆尝,進(jìn)而重新建立 user 表。

假設(shè) user 表有 id,username,email 三個(gè)字段因悲,那么可以再 up 方法中寫

public function up()
{
    Schema::create('user', function (Blueprint $table) {
        $table->increments('id')->index()->comment('用戶id');
        $table->string('name')->default('')->comment('用戶名');
        $table->string('email')->nullable()->comment('用戶郵箱');
        $table->timestamps();
    });
}

一般,我們的邏輯會(huì)在閉包函數(shù)中寫勺爱。上面的代碼晃琳,即時(shí)不能完全明白,也可以大概猜出以下幾點(diǎn):

  • 我們操作的表是 user 表琐鲁。
  • user 表中定義了 id 字段卫旱,因?yàn)檎{(diào)用了 increments 方法,所以 id 為 auto_increment围段,調(diào)用了 index 方法說明給 id 添加了索引顾翼,最后 comment 等同于注釋。
  • 有了 id 的經(jīng)驗(yàn)奈泪,那么 name 字段也很好理解了适贸,string 方法說明 name 是 varchar/char 類型的灸芳,default 定義了 name 字段的默認(rèn)值。
  • email 字段 調(diào)用了 nullable 方法說明運(yùn)行 email 字段為空拜姿。
  • 定義字段結(jié)構(gòu)的時(shí)候可以使用鏈?zhǔn)秸{(diào)用的方式烙样。

Laravel 中的方法是滿足你對 sql 語句的所有操作,如果你需要定義一個(gè)類型為 text 的字段蕊肥,那么可以調(diào)用 text() 方法谒获,更多的方法說明可以參見文檔 Laravel 數(shù)據(jù)庫結(jié)構(gòu)構(gòu)造器

我們已經(jīng)編寫好了 user 表的結(jié)構(gòu)壁却,接下來執(zhí)行 php artisan migrate批狱,Laravel 會(huì)根據(jù) create 方法自動(dòng)為我們創(chuàng)建 user 表。至此展东,我們已經(jīng)成功的通過 Larvel 的遷移功能來實(shí)現(xiàn)創(chuàng)建表赔硫。

Rollback

使用 Laravel 的遷移功能可以有后悔藥吃。

執(zhí)行 php artisan migrate 創(chuàng)建 user 表之后琅锻,覺得不行卦停,不要 user 這張表,于是你打算刪除這張表恼蓬。那么這時(shí)候我們就要使用剛剛說到的 down 方法了惊完。

public function down()
{
    Schema::dropIfExists('user');
}

這里 Laarvel 已經(jīng)為我們寫好邏輯了,dropIfExists 函數(shù)就是用來刪除表处硬,我們只需要執(zhí)行 php artisan migrate :rollback 就可以回滾到執(zhí)行 php artisan migrate 之前的狀態(tài)小槐。

重命名表

除了創(chuàng)建表,也可以用遷移記錄表的其他任何操作荷辕,包括修改表屬性凿跳,修改字段等等操作。這里再舉個(gè)例子說明如何用遷移來對表進(jìn)行重命名疮方。

  • 假設(shè)有表 user控嗜,我們需要對它重命名為 users。首先要執(zhí)行 php artisan make:migration rename_user_to_users --table user 來創(chuàng)建遷移文件骡显。
  • up 方法中寫我們要重命名表的邏輯疆栏。

public function up()
{
    Schema::table('user', function (Blueprint $table) {
        Schema::rename('user','users');
    });
}
  • 為了可以 rollback 可以順利執(zhí)行,我們還需要在 down 方法中編寫撤銷重命名操作的邏輯惫谤。
public function up()
{
    Schema::table('user', function (Blueprint $table) {
        //
        Schema::rename('users','user');
    });
}
  • 最后執(zhí)行 php artisan migrate 就就可以完成對 user 表的重命名操作壁顶。如果需要回滾,只要執(zhí)行 php artisan migrate:rollback溜歪。

你會(huì)發(fā)現(xiàn)若专,如果執(zhí)行一次遷移之后,如果執(zhí)行第二次遷移是不會(huì)重復(fù)執(zhí)行的蝴猪,這是因?yàn)?Laravel 會(huì)在數(shù)據(jù)庫中建立一張 migrations 的表來記錄哪些已經(jīng)進(jìn)行過遷移调衰。

基本的 migration 介紹就到這里膊爪,以上的內(nèi)容可以應(yīng)對大部分的需求,如果需要更詳細(xì)的介紹窖式,可能需要閱讀 Laravel 那不知所云的文檔了蚁飒。:)

Seeder

Laravel 中除了 migration 之外,還有一個(gè) seeder 的東西萝喘,這個(gè)東西用于做數(shù)據(jù)填充淮逻。假設(shè)項(xiàng)目開發(fā)中需要有一些測試數(shù)據(jù),那么同樣可以通過編寫 php 代碼來填充測試數(shù)據(jù)阁簸,那么通過 git 同步代碼爬早,所有的人都可以擁有一份同樣的測試數(shù)據(jù)。

同樣启妹,數(shù)據(jù)填充在 Laravel 中被稱為 Seeder筛严,如果需要對某張表填充數(shù)據(jù),需要先建立一個(gè) seeder饶米。通過執(zhí)行 php artisan make:seeder UserTableSeeder 來生成一個(gè) seeder 類桨啃。這里我們希望填充數(shù)據(jù)的表示 test 表,所以名字為 UserTableSeeder檬输。當(dāng)然這個(gè)名字不是強(qiáng)制性的照瘾,只是為了做到見名知意。

創(chuàng)建 UserTableSeeder 之后會(huì)在 database/seeders 目錄下生成一個(gè) UserTableSeeder 類丧慈,這個(gè)類只有一個(gè) run 方法析命。你可以在 run 方法中寫插入數(shù)據(jù)庫的代碼。假設(shè)我們使用 DB facade 來向 test 表插入數(shù)據(jù)逃默。

class UserTableSeeder extends Seeder
{

    public function run()
    {
        DB::table('users')->insert($insertData);
    }
}

編寫完代碼之后鹃愤,執(zhí)行 php artsian db:seeder --class= UserTableSeeder 來進(jìn)行數(shù)據(jù)填充。執(zhí)行完畢之后查看數(shù)據(jù)庫已經(jīng)有數(shù)據(jù)了完域。

如果我們有多個(gè)表要進(jìn)行數(shù)據(jù)填充软吐,那么不可能在編寫完 php 代碼之后,逐個(gè)的執(zhí)行 php artisan db:seeder --class=xxxx 來進(jìn)行填充吟税。有一個(gè)簡便的方法关噪。在 DatabaseSeederrun 方法中添加一行 $this->call(UserTableSeeder::class);,然后執(zhí)行 php artisan db:seeder乌妙,那么 Laravel 就會(huì)執(zhí)行 DatabaseSeeder 中的 run 方法,然后逐個(gè)執(zhí)行遷移建钥。

和 migration 不同藤韵,如果多次執(zhí)行 php artisan db:seeder 就會(huì)進(jìn)行多次數(shù)據(jù)填充。

加入你想一次性插入大量的測試數(shù)據(jù) 熊经,那么在 run 方法中使用 DB facade 來逐個(gè)插入顯然不是一個(gè)好的方法泽艘。Laravel 中提供了一種模型工廠的方式來創(chuàng)建創(chuàng)建大量的數(shù)據(jù)欲险。

模型工廠

模型工廠,意味著本質(zhì)其實(shí)是一個(gè)工廠模式匹涮。那么天试,在使用模型工廠創(chuàng)建數(shù)據(jù)需要做兩件事情

  1. 創(chuàng)建工廠,定義好工廠要返回的數(shù)據(jù)然低。
  2. 調(diào)用工廠獲取數(shù)據(jù)喜每。

Laravel 中通過執(zhí)行 php artisan make:factory UserFactory --model=User 來為 User Model 創(chuàng)建一個(gè)工廠類,該文件會(huì)放在 database/factory 目錄下雳攘。打開該文件可以看到如下代碼:

$factory->define(App\User::class, function (Faker $faker) {
    return [
        //
    ];
});

這里带兜, return 的值就是我們第 2 步調(diào)用工廠獲取到的數(shù)據(jù)。生成數(shù)據(jù)的邏輯也只需要寫在閉包函數(shù)中就可以吨灭。這里需要提一下 Faker 這個(gè)類刚照。這是一個(gè)第三方庫,Laravel 集成了這個(gè)第三方庫喧兄。這個(gè)庫的作用很好玩:用于生成假數(shù)據(jù)无畔。假設(shè) User 表需要插入 100 個(gè)用戶,那么就需要 100 個(gè) username吠冤,那么你就不必自己寫邏輯生成大量的 test01浑彰,test02 這樣子幼稚的假數(shù)據(jù),直接使用 Faker 類咨演,會(huì)替你生成大量逼真的 username闸昨。(我也不知道這個(gè)算不算無聊了 :)。薄风。饵较。)。

現(xiàn)在假設(shè) User 表有 id, email, username 三個(gè)字段遭赂,那么我要生成 100 個(gè)用戶循诉,首先在工廠類中實(shí)現(xiàn)邏輯。

$factory->define(App\Models\User::class, function (Faker $faker) {
    return [
        // 直接調(diào)用 faker API 生成假數(shù)據(jù)撇他,更多 faker 相關(guān)查看 文檔茄猫。
        'username' => $faker->name,
        'email' => $faker->unique()->safeEmail,
    ];
});

現(xiàn)在,我們已經(jīng)定義好了工廠困肩,現(xiàn)在我們就要在 UserSeeder@run 函數(shù)中使用模型工廠來生成測試數(shù)據(jù)划纽。


class UserTableSeeder extends Seeder
{

    public function run()
    {
        factory(App\User::class)->times(10)->make()->each(function($user,$index){
            $user->save();
        });
    }
}

run 函數(shù)中這一波行云流水的鏈?zhǔn)秸{(diào)用在我剛剛開始接觸 Laravel 的時(shí)候也是一臉黑線,不過習(xí)慣之后感覺這代碼可讀性確實(shí)很強(qiáng)

  • factory(App\User::class) 指明返回哪個(gè)工廠锌畸,參數(shù) App\User::class 就是工廠的唯一標(biāo)識(shí)勇劣。這里我們在定義工廠的時(shí)候 define 的第一個(gè)參數(shù)已經(jīng)指明了。
  • ->times(10) 指明需要工廠模式生成 10 個(gè) User 數(shù)據(jù)。即會(huì)調(diào)用 10 次 define 函數(shù)的第二個(gè)參數(shù)比默。
  • ->make() 把生成的 10 個(gè) User 數(shù)據(jù)封裝成 Laravel 中的集合對象幻捏。
  • ->each() 是 Laravel 集合中的函數(shù),each 函數(shù)會(huì)針對集合中的每個(gè)元素進(jìn)行操作命咐。這里直接把數(shù)據(jù)保存到數(shù)據(jù)庫篡九。

好了,數(shù)據(jù)遷移和數(shù)據(jù)填充的基本操作也就這些了醋奠。更多復(fù)雜的用法榛臼。。钝域。讽坏。也不一定能用上。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末例证,一起剝皮案震驚了整個(gè)濱河市路呜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌织咧,老刑警劉巖胀葱,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異笙蒙,居然都是意外死亡抵屿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門捅位,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轧葛,“玉大人,你說我怎么就攤上這事艇搀∧虺叮” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵焰雕,是天一觀的道長衷笋。 經(jīng)常有香客問我,道長矩屁,這世上最難降的妖魔是什么辟宗? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮吝秕,結(jié)果婚禮上泊脐,老公的妹妹穿的比我還像新娘。我一直安慰自己烁峭,他們只是感情好晨抡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般耘柱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棍现,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天调煎,我揣著相機(jī)與錄音伯复,去河邊找鬼祝拯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛襟锐,可吹牛的內(nèi)容都是我干的谎僻。 我是一名探鬼主播娄柳,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼艘绍!你這毒婦竟也來了赤拒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤诱鞠,失蹤者是張志新(化名)和其女友劉穎挎挖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體航夺,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蕉朵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阳掐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片始衅。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缭保,靈堂內(nèi)的尸體忽然破棺而出汛闸,到底是詐尸還是另有隱情,我是刑警寧澤涮俄,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布蛉拙,位于F島的核電站,受9級特大地震影響彻亲,放射性物質(zhì)發(fā)生泄漏孕锄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一苞尝、第九天 我趴在偏房一處隱蔽的房頂上張望畸肆。 院中可真熱鬧,春花似錦宙址、人聲如沸轴脐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽大咱。三九已至恬涧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碴巾,已是汗流浹背溯捆。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厦瓢,地道東北人提揍。 一個(gè)月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像煮仇,于是被迫代替她去往敵國和親劳跃。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容