如何在Laravel中執(zhí)行數(shù)據(jù)庫遷移

laravel數(shù)據(jù)庫遷移通過php代碼管理數(shù)據(jù)庫結(jié)構(gòu)變更,提供版本控制功能。1. 創(chuàng)建遷移文件:使用artisan命令生成帶時間戳的遷移文件并定義up()和down()方法;2. 執(zhí)行遷移:運行migrate命令按順序執(zhí)行未應用的遷移;3. 回滾遷移:使用rollback撤銷最近一次遷移,refresh重新運行所有遷移,reset僅回滾所有遷移;4. 多人協(xié)作:遵循不修改已提交遷移、拉取后先遷移、解決沖突時保留所有遷移文件等原則;5. 結(jié)構(gòu)變更:支持添加/修改/刪除列、重命名表或列、添加索引和外鍵、直接執(zhí)行sql語句等操作,實現(xiàn)全面的數(shù)據(jù)庫模式管理。

如何在Laravel中執(zhí)行數(shù)據(jù)庫遷移

laravel的數(shù)據(jù)庫遷移功能,說白了,就是一套幫你管理數(shù)據(jù)庫結(jié)構(gòu)變更的工具。它讓你能用PHP代碼來定義數(shù)據(jù)庫表的創(chuàng)建、修改、刪除等操作,然后通過命令行工具輕松地在不同環(huán)境(比如開發(fā)、測試、生產(chǎn))之間同步這些變更。對我來說,這簡直是版本控制在數(shù)據(jù)庫層面的完美實踐,省去了手動sql的繁瑣和出錯風險。

解決方案

要在Laravel中執(zhí)行數(shù)據(jù)庫遷移,核心流程其實就那么幾步,相當直觀。

首先,你需要創(chuàng)建一個遷移文件。這就像是告訴Laravel:“我要對數(shù)據(jù)庫做點什么了。” 你可以通過Artisan命令行工具來完成:

php artisan make:migration create_products_table --create=products

這條命令會生成一個類似 2023_10_27_123456_create_products_table.php 的文件在 database/migrations 目錄下。文件名里的時間戳確保了遷移的執(zhí)行順序。–create=products 這個參數(shù)會幫你預填充一些創(chuàng)建表的基礎(chǔ)代碼,省事不少。

打開這個新生成的遷移文件,你會看到兩個主要的方法:up() 和 down()。

up() 方法是當你的遷移被執(zhí)行時(也就是“跑起來”的時候)會運行的代碼。你在這里定義數(shù)據(jù)庫結(jié)構(gòu)的變更。比如,創(chuàng)建一個 products 表:

<?php  use IlluminateDatabaseMigrationsMigration; use IlluminateDatabaseSchemaBlueprint; use IlluminateSupportFacadesSchema;  return new class extends Migration {     /**      * Run the migrations.      */     public function up(): void     {         Schema::create('products', function (Blueprint $table) {             $table->id();             $table->string('name');             $table->text('description')->nullable();             $table->decimal('price', 8, 2);             $table->integer('stock')->default(0);             $table->timestamps(); // created_at and updated_at         });     }      /**      * Reverse the migrations.      */     public function down(): void     {         Schema::dropIfExists('products');     } };

down() 方法則是在你回滾(撤銷)這個遷移時會執(zhí)行的代碼。它應該做的事情是撤銷 up() 方法所做的所有變更。對于創(chuàng)建表的操作,down() 方法通常就是刪除這個表。這保證了你的數(shù)據(jù)庫狀態(tài)可以向前和向后平滑地轉(zhuǎn)換,這一點在開發(fā)和調(diào)試時尤其有用。

定義好遷移文件后,最后一步就是執(zhí)行它:

php artisan migrate

這條命令會查找所有尚未執(zhí)行的遷移文件,并按時間戳順序運行它們的 up() 方法。Artisan 會在你的數(shù)據(jù)庫中創(chuàng)建一個 migrations 表來記錄哪些遷移已經(jīng)被執(zhí)行過,避免重復運行。

遷移文件寫錯了怎么辦?如何快速回滾或重置數(shù)據(jù)庫結(jié)構(gòu)?

這幾乎是每個開發(fā)者都會遇到的情況,尤其是項目初期,表結(jié)構(gòu)經(jīng)常變動。我剛開始接觸Laravel遷移的時候,也犯過這樣的錯誤:寫完一個遷移,跑起來發(fā)現(xiàn)字段名拼錯了,或者漏了一個關(guān)鍵字段。

最直接的補救措施是使用 rollback 命令:

php artisan migrate:rollback

這個命令會回滾最近一批執(zhí)行的遷移。它會運行這些遷移文件中的 down() 方法。如果你只跑了一個新的遷移,那么它就只會回滾這一個。但如果上次你一次性跑了三個新的遷移,rollback 也會把這三個都回滾掉。

有時候,你可能想更徹底一點,直接把數(shù)據(jù)庫結(jié)構(gòu)恢復到“初始狀態(tài)”,或者干脆想把所有遷移都撤銷,然后重新跑一遍。這時候,refresh 命令就派上用場了:

php artisan migrate:refresh

這個命令會先回滾所有已執(zhí)行的遷移(即運行所有遷移的 down() 方法),然后再次運行所有遷移(即運行所有遷移的 up() 方法)。這在開發(fā)階段非常方便,它能讓你快速清空并重建數(shù)據(jù)庫結(jié)構(gòu)。但請注意,在生產(chǎn)環(huán)境使用 migrate:refresh 意味著會丟失所有數(shù)據(jù),所以務必謹慎。

如果你只是想回滾某個特定的遷移,或者只想回滾最近的N個遷移,可以加上 –step 參數(shù):

php artisan migrate:rollback --step=1 // 回滾最近的一個批次 php artisan artisan migrate:rollback --step=3 // 回滾最近的三個批次

還有個 migrate:reset 命令,它會回滾所有遷移,但不會重新運行它們。這在你想徹底清空數(shù)據(jù)庫結(jié)構(gòu)時很有用。

php artisan migrate:reset

記住,down() 方法的正確實現(xiàn)至關(guān)重要。如果 down() 方法沒有正確地撤銷 up() 方法的操作,那么你的回滾操作就可能出現(xiàn)問題,甚至導致數(shù)據(jù)不一致。

多個開發(fā)者協(xié)同工作時,遷移如何管理?

團隊協(xié)作是現(xiàn)代軟件開發(fā)的核心,而數(shù)據(jù)庫遷移在這種場景下尤其需要一套清晰的策略。我見過一些團隊,因為遷移管理不善,導致開發(fā)環(huán)境混亂,甚至影響到部署。

核心原則是:已提交并執(zhí)行的遷移,除非萬不得已,不要去修改它。

當多個開發(fā)者在同一個項目上工作時,通常會遇到以下情況:

  1. 拉取最新代碼后: 每次從版本控制系統(tǒng)(如git)拉取了團隊成員的新代碼后,你的第一反應就應該是運行 php artisan migrate。這會確保你的本地數(shù)據(jù)庫結(jié)構(gòu)與團隊的最新進展保持同步。如果你的同事添加了新的遷移文件,這條命令就會把這些新的結(jié)構(gòu)變更應用到你的本地數(shù)據(jù)庫。
  2. 創(chuàng)建新的遷移: 每個開發(fā)者在需要修改數(shù)據(jù)庫結(jié)構(gòu)時,都應該創(chuàng)建新的遷移文件,而不是去修改已存在的、其他同事可能已經(jīng)執(zhí)行過的遷移。例如,如果 products 表需要新增一個 weight 字段,你應該創(chuàng)建一個 add_weight_to_products_table 的新遷移,而不是去修改 create_products_table。
  3. 合并沖突: 遷移文件因為帶有時間戳,通常不太容易出現(xiàn)合并沖突。但如果兩個開發(fā)者幾乎同時創(chuàng)建了兩個遷移文件,并且它們的名稱或內(nèi)容有重疊,Git可能會提示沖突。解決沖突時,要確保兩個遷移文件的內(nèi)容都被正確地保留下來,并且它們在執(zhí)行順序上是合理的。通常,只需確保兩個文件都存在于 database/migrations 目錄下,并被Git正確合并即可。
  4. 數(shù)據(jù)播種 (Seeding): 遷移只負責數(shù)據(jù)庫結(jié)構(gòu),不負責數(shù)據(jù)。在團隊協(xié)作中,為了保持開發(fā)環(huán)境數(shù)據(jù)的一致性,通常會配合使用數(shù)據(jù)播種器(Seeders)。在運行 php artisan migrate 之后,通常會運行 php artisan db:seed(或 php artisan migrate –seed),來填充一些基礎(chǔ)數(shù)據(jù),確保所有開發(fā)者的環(huán)境都有相同的起點數(shù)據(jù)。

我的經(jīng)驗是,保持溝通,并且約定好數(shù)據(jù)庫結(jié)構(gòu)變更的提交和拉取流程,可以大大減少這類問題。例如,約定在每次開始新功能開發(fā)前,都先 git pull 并 php artisan migrate。

除了創(chuàng)建表,遷移還能做些什么?

Laravel的遷移功能遠不止于創(chuàng)建表這么簡單,它實際上是一個強大的數(shù)據(jù)庫結(jié)構(gòu)管理工具,能夠處理各種復雜的結(jié)構(gòu)變更。我個人覺得,它的靈活性是其最大的亮點之一。

  1. 添加、修改和刪除列: 這是最常見的操作之一。你可以輕松地向現(xiàn)有表添加新列、修改現(xiàn)有列的類型或?qū)傩裕踔羷h除不再需要的列。

    • 添加列:
      Schema::table('users', function (Blueprint $table) {     $table->string('address')->nullable();     $table->string('phone')->after('email'); // 在email列之后添加 });
    • 修改列: 這通常需要 doctrine/dbal 庫的支持。
      Schema::table('users', function (Blueprint $table) {     $table->string('name', 100)->change(); // 將name列長度改為100     $table->text('description')->nullable()->change(); // 將description列設為可空 });

      安裝 doctrine/dbal:composer require doctrine/dbal

    • 刪除列:
      Schema::table('users', function (Blueprint $table) {     $table->dropColumn('address'); });
  2. 重命名表或列: 當你發(fā)現(xiàn)最初的命名不夠理想時,遷移可以幫你安全地重命名。

    • 重命名表:
      Schema::rename('old_table_name', 'new_table_name');
    • 重命名列:
      Schema::table('users', function (Blueprint $table) {     $table->renameColumn('old_name', 'new_name'); });
  3. 添加索引和外鍵: 優(yōu)化查詢性能和維護數(shù)據(jù)完整性是數(shù)據(jù)庫設計的關(guān)鍵。

    • 添加索引:
      Schema::table('posts', function (Blueprint $table) {     $table->index('user_id'); // 普通索引     $table->unique('slug'); // 唯一索引     $table->fullText('content'); // 全文索引 });
    • 添加外鍵:
      Schema::table('posts', function (Blueprint $table) {     $table->foreignId('user_id')->constrained()->onDelete('cascade');     // 或者更詳細的定義     // $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); });
  4. 刪除索引和外鍵:

    Schema::table('posts', function (Blueprint $table) {     $table->dropIndex(['user_id']);     $table->dropUnique(['slug']);     $table->dropForeign(['user_id']); // 或者指定外鍵名 });
  5. 直接執(zhí)行sql語句 雖然不推薦,但在某些復雜或特定數(shù)據(jù)庫的場景下,你可能需要直接執(zhí)行原生的SQL語句。

    DB::statement('ALTER TABLE users ADD COLUMN points INT DEFAULT 0;'); // 在down()方法中 DB::statement('ALTER TABLE users DROP COLUMN points;');

    需要引入 use IlluminateSupportFacadesDB;

總的來說,Laravel的遷移系統(tǒng)提供了一個非常全面的API來管理數(shù)據(jù)庫模式,它讓數(shù)據(jù)庫變更變得可追溯、可管理,并且極大地降低了開發(fā)和部署過程中的風險。熟練掌握這些功能,能讓你的開發(fā)工作流程更加順暢。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊9 分享