【PHP】ThinkPHP8 数据库迁移与数据填充完全指南

小破孩
2025-07-26 / 0 评论 / 2 阅读 / 正在检测是否收录...

ThinkPHP8 数据库迁移与数据填充完全指南(官方文档补充版)

一、安装与配置

1. 安装迁移扩展

composer require topthink/think-migration

2. 配置文件说明

  • 配置文件位于 config/database.php
  • 默认迁移表名:think_migration
  • 支持多数据库连接

3. 环境要求

  • PHP >= 8.1
  • ThinkPHP >= 8.0
  • 建议使用 InnoDB 引擎(支持事务)

二、迁移文件操作

1. 创建迁移文件

# 创建基础迁移文件
php think migrate:create CreateUsersTable

# 创建带表名的迁移文件(自动生成基础结构)
php think migrate:create AddEmailToUsersTable --table=users

# 指定数据库连接
php think migrate:create CreateLogsTable --connection=log

2. 迁移文件结构

生成的迁移文件位于 database/migrations,示例:

<?php

use think\migration\Migrator;
use think\migration\db\Column;

class CreateUsersTable extends Migrator
{
    /**
     * 执行迁移(向上操作)
     */
    public function up()
    {
        $table = $this->table('users');
        $table->addColumn('name', 'string', ['limit' => 50])
              ->addColumn('email', 'string', ['limit' => 100, 'unique' => true])
              ->addColumn('password', 'string', ['limit' => 100])
              ->addTimestamps()  // 自动添加 create_time 和 update_time 字段
              ->create();
    }

    /**
     * 回滚迁移(向下操作)
     */
    public function down()
    {
        $this->dropTable('users');
    }
}

三、常用字段类型

字段类型描述示例用法
integer整数类型->addColumn('age', 'integer')
biginteger大整数类型->addColumn('user_id', 'biginteger')
string字符串类型->addColumn('name', 'string', ['limit' => 50])
text长文本类型->addColumn('content', 'text')
datetime日期时间类型->addColumn('created_at', 'datetime')
timestamp时间戳类型->addColumn('updated_at', 'timestamp')
boolean布尔类型->addColumn('status', 'boolean', ['default' => 0])
decimal高精度小数->addColumn('price', 'decimal', ['precision' => 10, 'scale' => 2])
enum枚举类型->addColumn('gender', 'enum', ['values' => ['male', 'female', 'other']])

四、表结构操作

1. 创建表

public function up()
{
    $table = $this->table('users', [
        'engine'    => 'InnoDB',
        'charset'   => 'utf8mb4',
        'comment'   => '用户表',
        'collation' => 'utf8mb4_unicode_ci'
    ]);
    
    $table->addColumn('id', 'integer', ['identity' => true])  // 自增ID(默认主键)
          ->addColumn('username', 'string', ['limit' => 30])
          ->addColumn('email', 'string', ['limit' => 100, 'unique' => true])
          ->addColumn('password', 'string', ['limit' => 100])
          ->addColumn('status', 'boolean', ['default' => 1])
          ->addIndex(['username'])  // 普通索引
          ->addUniqueIndex(['email'])  // 唯一索引
          ->addTimestamps()  // 自动添加 create_time 和 update_time
          ->addSoftDelete()  // 添加 delete_time 软删除字段
          ->create();
}

2. 修改表

添加字段:

public function up()
{
    $this->table('users')
         ->addColumn('phone', 'string', ['limit' => 20, 'after' => 'email'])
         ->update();
}

修改字段:

public function up()
{
    $this->table('users')
         ->changeColumn('phone', 'string', ['limit' => 11, 'default' => ''])
         ->update();
}

删除字段:

public function up()
{
    $this->table('users')
         ->removeColumn('phone')
         ->update();
}

3. 添加外键约束

public function up()
{
    $this->table('posts')
         ->addColumn('user_id', 'integer')
         ->addColumn('title', 'string')
         ->addColumn('content', 'text')
         ->addForeignKey('user_id', 'users', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
         ->update();
}

五、执行迁移命令

1. 执行所有未迁移的文件

php think migrate:run

2. 回滚上一次迁移

php think migrate:rollback

3. 回滚到指定版本

php think migrate:rollback --target=20250726101500  # 指定时间戳

4. 重置所有迁移(先回滚再执行)

php think migrate:reset

5. 刷新数据库(重置并重新执行所有迁移)

php think migrate:refresh

6. 查看迁移状态

php think migrate:status

7. 指定数据库连接

php think migrate:run --connection=db_log  # 指定日志数据库

六、数据填充操作

1. 创建数据填充文件

php think seed:create Users  # 创建Users表的数据填充器

2. 编写数据填充逻辑

<?php

use think\migration\Seeder;
use think\facade\Db;

class Users extends Seeder
{
    /**
     * 填充数据
     */
    public function run()
    {
        $data = [];
        for ($i = 1; $i <= 10; $i++) {
            $data[] = [
                'username'  => 'user' . $i,
                'email'     => 'user' . $i . '@example.com',
                'password'  => password_hash('123456', PASSWORD_DEFAULT),
                'create_time' => date('Y-m-d H:i:s'),
                'update_time' => date('Y-m-d H:i:s')
            ];
        }

        // 使用批量插入提高性能
        Db::name('users')->insertAll($data);
    }
}

3. 执行数据填充

php think seed:run  # 执行所有填充器
php think seed:run --seeder Users  # 执行指定填充器

七、高级技巧

1. 使用 change() 方法(简化双向操作)

public function change()
{
    $table = $this->table('users');
    
    if (!$table->exists()) {
        // 创建表
        $table->addColumn('username', 'string')
              ->addColumn('email', 'string')
              ->create();
    } else {
        // 修改表
        $table->addColumn('phone', 'string')
              ->update();
    }
}

2. 使用事务

public function up()
{
    $this->getAdapter()->beginTransaction();
    try {
        $this->table('table1')->addColumn(...)->create();
        $this->table('table2')->addColumn(...)->create();
        $this->getAdapter()->commit();
    } catch (\Exception $e) {
        $this->getAdapter()->rollBack();
        throw $e;
    }
}

3. 创建数据库快照

php think migrate:snapshot  # 创建当前数据库结构快照

4. 指定迁移文件路径

php think migrate:run --path=database/migrations/custom  # 指定自定义路径

八、最佳实践

1. 命名规范

  • 迁移文件:YYYYMMDDHHMMSS_表名_操作.php(自动生成)
  • 表名:使用小写字母和下划线(如 user_info
  • 字段名:使用小写字母和下划线(如 create_time

2. 避免复杂SQL

  • 单个迁移文件只做单一变更
  • 避免在迁移中执行数据迁移操作

3. 测试迁移

  • 在开发环境充分测试
  • 使用测试数据库验证回滚功能

4. 生产环境注意事项

  • 迁移前备份数据库
  • 使用 --pretend 参数预览变更
  • 避免在高峰期执行大型迁移

5. 团队协作

  • 迁移文件提交到版本控制系统
  • 避免多人同时修改同一迁移文件
  • 拉取代码后先执行 php think migrate:run

九、常见问题与解决方案

1. 迁移文件冲突

  • 问题:多个迁移文件时间戳相近导致执行顺序异常
  • 解决方案:使用 --timestamp 参数手动指定时间戳

    php think migrate:create NewTable --timestamp=20250726153000

2. 外键约束错误

  • 问题:删除表时外键约束阻止操作
  • 解决方案:在 down() 方法中先删除外键

    public function down()
    {
        $this->table('posts')
             ->dropForeignKey('user_id')
             ->update();
        $this->dropTable('posts');
    }

3. 数据填充重复问题

  • 问题:多次执行填充器导致数据重复
  • 解决方案:在填充前清空表

    public function run()
    {
        Db::name('users')->delete(true);  // 清空表
        // 填充新数据
    }

4. 迁移性能问题

  • 问题:大型表迁移缓慢
  • 解决方案

    • 分批次执行数据迁移
    • 使用数据库原生工具导入大型数据
    • 避免在迁移中使用复杂查询
0

评论 (0)

取消