数据库迁移
⚠️ 注意:数据库迁移功能尚未实现
本文档描述的是计划中的迁移系统设计。当前版本(截至 v1.x)尚未实现此功能。以下内容仅供参考。
如需管理数据库结构,请直接使用 SQL 或第三方迁移工具(如 Phinx、Laravel Migration 等)。
数据库迁移提供了一种版本化管理数据库结构变更的方式,使团队协作中的数据库 schema 变更可追溯、可回滚。
基本概念
迁移文件位于项目的迁移目录中,每个迁移文件包含 up()(执行迁移)和 down()(回滚迁移)两个方法:
- up():应用迁移,通常用于创建表、添加字段、创建索引等
- down():撤销迁移,通常是 up() 的逆向操作
创建迁移文件
bash
# 创建新的迁移文件
php viswoole migrate:create create_users_table生成的迁移文件结构如下:
php
<?php
use Viswoole\Database\Migration\Migration;
use Viswoole\Database\Schema\Blueprint;
use Viswoole\Database\Schema\Schema;
class CreateUsersTable extends Migration
{
/**
* 执行迁移
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50);
$table->string('email', 100)->unique();
$table->string('password', 255);
$table->tinyInteger('status')->default(1);
$table->timestamps();
$table->softDeletes();
});
}
/**
* 回滚迁移
*/
public function down(): void
{
Schema::dropIfExists('users');
}
}常用字段类型
| 方法 | 说明 | 对应 MySQL 类型 |
|---|---|---|
$table->increments('id') | 自增主键 | INT UNSIGNED AUTO_INCREMENT PRIMARY KEY |
$table->bigIncrements('id') | 大整数自增主键 | BIGINT UNSIGNED AUTO_INCREMENT |
$table->string('name', 50) | 可变长字符串 | VARCHAR(50) |
$table->text('content') | 长文本 | TEXT |
$table->integer('age') | 整数 | INT |
$table->bigInteger('score') | 大整数 | BIGINT |
$table->tinyInteger('status') | 小整数 | TINYINT |
$table->decimal('price', 10, 2) | 精确小数 | DECIMAL(10,2) |
$table->float('rate') | 浮点数 | FLOAT |
$table->boolean('is_active') | 布尔值 | TINYINT(1) |
$table->date('birthday') | 日期 | DATE |
$table->dateTime('published_at') | 日期时间 | DATETIME |
$table->timestamp('created_at') | 时间戳 | TIMESTAMP |
$table->json('meta') | JSON 类型 | JSON |
$table->enum('level', ['A','B','C']) | 枚举 | ENUM('A','B','C') |
常用修饰符
修饰符可链式调用来进一步定义字段属性:
php
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
// 默认值
$table->string('name', 50)->default('匿名');
// 允许为空
$table->string('avatar')->nullable();
// 唯一索引
$table->string('email', 100)->unique();
// 注释
$table->text('remark')->comment('备注信息');
// 在某个字段之后(MySQL 特有)
$table->string('nickname')->after('name');
// 无符号
$table->integer('age')->unsigned();
});常用辅助方法
| 方法 | 说明 |
|---|---|
$table->timestamps() | 创建 created_at 和 updated_at 字段 |
$table->softDeletes() | 创建 deleted_at 软删除字段 |
$table->rememberToken() | 创建 remember_token 字段(用于"记住我"功能) |
$table->dropTimestamps() | 移除时间戳字段 |
$table->dropSoftDeletes() | 移除软删除字段 |
修改表结构
添加字段
php
class AddPhoneToUsersTable extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone', 20)->nullable()->after('email');
$table->string('address', 255)->nullable()->comment('收货地址');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['phone', 'address']);
});
}
}修改字段
php
class ModifyUsersEmailField extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
// 修改 email 字段长度
$table->string('email', 200)->change();
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('email', 100)->change();
});
}
}添加索引
php
class AddIndexToOrdersTable extends Migration
{
public function up(): void
{
Schema::table('orders', function (Blueprint $table) {
// 普通索引
$table->index('user_id');
// 组合索引
$table->index(['user_id', 'status']);
// 唯一索引
$table->unique('order_no');
// 指定索引名称
$table->index('created_at', 'idx_orders_created_at');
});
}
public function down(): void
{
Schema::table('orders', function (Blueprint $table) {
$table->dropIndex('idx_orders_created_at');
$table->dropUnique('orders_order_no_unique');
});
}
}执行迁移
bash
# 执行所有待处理的迁移
php viswoole migrate
# 执行迁移并填充数据
php viswoole migrate --seed
# 查看迁移状态
php viswoole migrate:status
# 回滚上一次迁移
php viswoole migrate:rollback
# 回滚所有迁移
php viswoole migrate:reset
# 回滚后重新执行所有迁移
php viswoole migrate:refresh完整示例
以下是用户系统的完整迁移文件集合:
php
<?php
// === 001_create_users_table.php ===
use Viswoole\Database\Migration\Migration;
use Viswoole\Database\Schema\Blueprint;
use Viswoole\Database\Schema\Schema;
class CreateUsersTable extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50)->comment('用户昵称');
$table->string('email', 100)->unique()->comment('邮箱');
$table->string('password', 255)->comment('密码哈希');
$table->string('phone', 20)->nullable()->comment('手机号');
$table->tinyInteger('status')->default(1)->comment('状态:1正常 0禁用');
$table->timestamps();
$table->softDeletes();
$table->index('status', 'idx_users_status');
$table->index('created_at', 'idx_users_created_at');
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
}
// === 002_create_profiles_table.php ===
class CreateProfilesTable extends Migration
{
public function up(): void
{
Schema::create('profiles', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->string('avatar', 255)->nullable()->comment('头像URL');
$table->text('bio')->nullable()->comment('个人简介');
$table->string('city', 50)->nullable()->comment('所在城市');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('profiles');
}
}
// === 003_create_orders_table.php ===
class CreateOrdersTable extends Migration
{
public function up(): void
{
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('order_no', 32)->unique()->comment('订单编号');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->decimal('total_amount', 12, 2)->default(0)->comment('订单总额');
$table->tinyInteger('status')->default(0)->comment('订单状态');
$table->timestamp('paid_at')->nullable()->comment('支付时间');
$table->timestamps();
$table->softDeletes();
$table->index('user_id', 'orders_user_id_index');
$table->index(['user_id', 'status'], 'orders_user_status_index');
$table->index('created_at', 'orders_created_at_index');
});
}
public function down(): void
{
Schema::dropIfExists('orders');
}
}最佳实践
- 命名规范:迁移文件采用描述性命名,如
create_users_table、add_phone_to_users_table - 可回滚:始终实现
down()方法,确保迁移可完全回滚 - 小步迭代:每次迁移只做一件事,避免大而全的迁移文件
- 团队协作:迁移文件纳入版本控制,团队成员拉取代码后执行
migrate即可同步数据库结构 - 生产环境谨慎操作:生产环境执行迁移前务必备份数据库
