数据库迁移 #

一、迁移概述 #

1.1 什么是迁移 #

迁移是数据库的版本控制系统,允许你用代码定义数据库结构,并与团队成员共享。

text
迁移的作用
├── 版本控制
│   ├── 记录数据库变更历史
│   └── 可回滚到任意版本
├── 团队协作
│   ├── 共享数据库结构
│   └── 同步数据库变更
└── 环境一致
    ├── 开发环境
    ├── 测试环境
    └── 生产环境

1.2 迁移文件位置 #

迁移文件存放在 database/migrations 目录下。

二、创建迁移 #

2.1 创建迁移文件 #

bash
# 创建迁移
php artisan make:migration create_users_table

# 指定表名
php artisan make:migration create_users_table --create=users

# 修改现有表
php artisan make:migration add_votes_to_users_table --table=users

2.2 迁移文件结构 #

php
// database/migrations/2024_01_01_000000_create_users_table.php

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

return new class extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

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

三、表结构构建 #

3.1 创建表 #

php
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

3.2 修改表 #

php
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->after('email');
});

3.3 删除表 #

php
Schema::dropIfExists('users');

3.4 重命名表 #

php
Schema::rename('users', 'members');

四、字段类型 #

4.1 常用字段类型 #

php
Schema::create('example', function (Blueprint $table) {
    // 数字类型
    $table->bigIncrements('id');        // 自增BIGINT主键
    $table->bigInteger('votes');        // BIGINT
    $table->integer('votes');           // INTEGER
    $table->mediumInteger('votes');     // MEDIUMINT
    $table->smallInteger('votes');      // SMALLINT
    $table->tinyInteger('votes');       // TINYINT
    $table->unsignedInteger('votes');   // UNSIGNED INTEGER
    $table->decimal('amount', 8, 2);    // DECIMAL
    $table->float('amount', 8, 2);      // FLOAT
    $table->double('amount', 8, 2);     // DOUBLE

    // 字符串类型
    $table->string('name', 100);        // VARCHAR
    $table->text('description');        // TEXT
    $table->mediumText('description');  // MEDIUMTEXT
    $table->longText('description');    // LONGTEXT
    $table->char('code', 10);           // CHAR

    // 日期时间类型
    $table->date('created_at');         // DATE
    $table->time('created_at');         // TIME
    $table->dateTime('created_at');     // DATETIME
    $table->timestamp('created_at');    // TIMESTAMP
    $table->timestamps();               // created_at, updated_at
    $table->softDeletes();              // deleted_at
    $table->year('birth_year');         // YEAR

    // 布尔类型
    $table->boolean('active');          // BOOLEAN

    // 枚举类型
    $table->enum('status', ['pending', 'active', 'inactive']);

    // JSON类型
    $table->json('options');            // JSON
    $table->jsonb('options');           // JSONB

    // 二进制类型
    $table->binary('data');             // BLOB

    // 其他类型
    $table->uuid('id');                 // UUID
    $table->ipAddress('ip');            // IP地址
    $table->macAddress('mac');          // MAC地址
    $table->geometry('position');       // GEOMETRY
    $table->point('position');          // POINT
    $table->rememberToken();            // remember_token
});

4.2 字段修饰符 #

php
Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();           // 允许NULL
    $table->string('name')->default('Guest');      // 默认值
    $table->string('email')->unique();             // 唯一索引
    $table->string('name')->first();               // 放在表首位
    $table->string('phone')->after('email');       // 放在某字段后
    $table->string('name')->comment('用户名');      // 注释
    $table->string('name')->charset('utf8mb4');    // 字符集
    $table->string('name')->collation('utf8mb4_unicode_ci'); // 排序规则
    $table->integer('votes')->unsigned();          // 无符号
    $table->integer('votes')->autoIncrement();     // 自增
    $table->string('name')->storedAs('expression'); // 存储生成列
    $table->string('name')->virtualAs('expression'); // 虚拟生成列
});

五、索引 #

5.1 创建索引 #

php
Schema::table('users', function (Blueprint $table) {
    // 主键
    $table->primary('id');
    $table->primary(['id', 'parent_id']);

    // 唯一索引
    $table->unique('email');
    $table->unique(['email', 'name']);

    // 普通索引
    $table->index('name');
    $table->index(['name', 'email']);

    // 全文索引
    $table->fullText('description');

    // 指定索引名称
    $table->unique('email', 'unique_email_index');
});

5.2 删除索引 #

php
Schema::table('users', function (Blueprint $table) {
    $table->dropPrimary('users_id_primary');
    $table->dropUnique('users_email_unique');
    $table->dropIndex('users_name_index');
    $table->dropFullText('users_description_fulltext');
});

5.3 外键约束 #

php
Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')
        ->constrained()
        ->onUpdate('cascade')
        ->onDelete('cascade');

    // 或
    $table->unsignedBigInteger('user_id');
    $table->foreign('user_id')
        ->references('id')
        ->on('users')
        ->onDelete('cascade');
});

5.4 删除外键 #

php
Schema::table('posts', function (Blueprint $table) {
    $table->dropForeign(['user_id']);
    $table->dropForeign('posts_user_id_foreign');
});

六、字段操作 #

6.1 添加字段 #

php
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->after('email');
    $table->string('address')->nullable();
});

6.2 修改字段 #

php
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
    $table->string('name', 50)->nullable()->change();
});

需要安装 doctrine/dbal

bash
composer require doctrine/dbal

6.3 重命名字段 #

php
Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
});

6.4 删除字段 #

php
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
    $table->dropColumn(['votes', 'avatar', 'location']);
});

七、运行迁移 #

7.1 执行迁移 #

bash
# 执行所有未执行的迁移
php artisan migrate

# 查看迁移状态
php artisan migrate:status

7.2 回滚迁移 #

bash
# 回滚最后一次迁移
php artisan migrate:rollback

# 回滚最近5次迁移
php artisan migrate:rollback --step=5

# 回滚所有迁移
php artisan migrate:reset

7.3 重置并重新迁移 #

bash
php artisan migrate:fresh

# 同时填充数据
php artisan migrate:fresh --seed

7.4 强制在生产环境运行 #

bash
php artisan migrate --force

八、迁移实战 #

8.1 创建用户表 #

php
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

8.2 创建文章表 #

php
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->string('title');
    $table->string('slug')->unique();
    $table->text('content');
    $table->enum('status', ['draft', 'published'])->default('draft');
    $table->timestamp('published_at')->nullable();
    $table->timestamps();
    $table->softDeletes();
    
    $table->index(['status', 'published_at']);
});

8.3 创建评论表 #

php
Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->foreignId('post_id')->constrained()->onDelete('cascade');
    $table->text('content');
    $table->morphs('commentable');  // 多态关联
    $table->timestamps();
    
    $table->index(['user_id', 'post_id']);
});

8.4 添加字段 #

php
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->nullable()->after('email');
    $table->string('avatar')->nullable()->after('phone');
    $table->json('preferences')->nullable()->after('avatar');
});

九、最佳实践 #

9.1 迁移命名规范 #

bash
# 创建表
create_users_table

# 添加字段
add_phone_to_users_table

# 修改字段
change_users_name_length

# 删除字段
remove_phone_from_users_table

# 创建索引
add_index_to_users_email

9.2 迁移顺序 #

text
迁移文件按时间戳排序执行:
2024_01_01_000000_create_users_table.php
2024_01_01_100000_create_posts_table.php
2024_01_02_000000_add_phone_to_users_table.php

9.3 回滚安全 #

php
public function down()
{
    // 确保回滚操作安全
    Schema::dropIfExists('users');
    
    // 或更精确的回滚
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('phone');
    });
}

9.4 生产环境注意事项 #

text
生产环境迁移注意事项:
1. 备份数据库
2. 先在测试环境验证
3. 避免删除重要数据
4. 使用事务包裹
5. 考虑大数据表迁移时间

十、常见问题 #

10.1 迁移卡住 #

bash
# 查看迁移状态
php artisan migrate:status

# 手动解决
php artisan migrate:rollback

10.2 外键约束错误 #

php
// 迁移顺序很重要
// 先创建被引用的表
Schema::create('users', function (Blueprint $table) {
    $table->id();
    // ...
});

// 再创建引用表
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    // ...
});

10.3 字段修改问题 #

bash
# 安装依赖
composer require doctrine/dbal

十一、总结 #

11.1 核心命令 #

命令 说明
make:migration 创建迁移
migrate 执行迁移
migrate:rollback 回滚迁移
migrate:fresh 重置迁移
migrate:status 查看状态

11.2 核心方法 #

方法 说明
Schema::create() 创建表
Schema::table() 修改表
Schema::drop() 删除表
$table->id() 自增主键
$table->timestamps() 时间戳
$table->foreignId() 外键

11.3 下一步 #

掌握了数据库迁移后,让我们继续学习 表单处理,了解Laravel表单操作!

最后更新:2026-03-28