PHP项目Symfony migration与版本

wen PHP项目 1

Symfony Migration 与版本管理详解

基础概念

Symfony 的迁移系统(DoctrineMigrationsBundle)用于管理数据库 schema 的版本变更,类似于 Git 管理代码版本。

PHP项目Symfony migration与版本

安装与配置

# 安装迁移包
composer require doctrine/doctrine-migrations-bundle
# 配置文件 (config/packages/doctrine_migrations.yaml)
doctrine_migrations:
    migrations_paths:
        'App\Migrations': '%kernel.project_dir%/migrations'
    storages:
        table_storage:
            table_name: 'migration_versions'

迁移命令大全

# 生成新的迁移(基于实体差异)
php bin/console make:migration
# 生成空迁移(自定义 SQL)
php bin/console make:migration --empty
# 执行迁移
php bin/console doctrine:migrations:migrate
# 回滚到指定版本
php bin/console doctrine:migrations:migrate App\Migrations\Version20210101120000
# 查看状态
php bin/console doctrine:migrations:status
# 查看列表
php bin/console doctrine:migrations:list
# 生成迁移的 SQL 语句(不执行)
php bin/console doctrine:migrations:dump-schema

迁移文件结构

// migrations/Version20230101000000.php
declare(strict_types=1);
namespace App\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20230101000000 extends AbstractMigration
{
    public function getDescription(): string
    {
        return '创建用户表';
    }
    public function up(Schema $schema): void
    {
        // 方法1: 使用 Schema builder
        $table = $schema->createTable('users');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
        $table->addColumn('username', 'string', ['length' => 100]);
        $table->addColumn('email', 'string', ['length' => 255]);
        $table->setPrimaryKey(['id']);
        // 方法2: 直接 SQL
        $this->addSql('CREATE TABLE users (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
    }
    public function down(Schema $schema): void
    {
        // 回滚操作
        $schema->dropTable('users');
        // 或者
        $this->addSql('DROP TABLE users');
    }
}

高级特性

// 1. 条件执行
public function isTransactional(): bool
{
    return false; // 不使用事务
}
// 2. 预检查
public function preUp(Schema $schema): void
{
    // 执行前的检查
}
// 3. 使用 Platform 特定 SQL
public function up(Schema $schema): void
{
    $platform = $this->connection->getDatabasePlatform();
    if ($platform instanceof MySqlPlatform) {
        $this->addSql('ALTER TABLE users ADD INDEX idx_username (username)');
    }
}
// 4. 使用参数绑定
public function up(Schema $schema): void
{
    $this->addSql('UPDATE users SET username = :name WHERE id = :id', [
        'name' => 'admin',
        'id' => 1
    ]);
}

版本管理最佳实践

1 命名规范

# 推荐命名:YYYYMMDDHHMMSS_描述
Version20230101120000_CreateUserTable.php
Version20230101130000_AddEmailToUser.php
Version20230101140000_CreateProductTable.php

2 工作流程

# 开发环境
1. 修改 Entity
2. 生成迁移:make:migration
3. 检查生成的 SQL
4. 执行迁移:migrate
5. 提交到版本控制
# 生产环境
1. 拉取代码
2. 执行迁移:migrations:migrate
3. 验证数据库状态

3 回滚策略

# 回滚到指定版本
php bin/console doctrine:migrations:migrate App\Migrations\Version20230101000000
# 查看迁移历史
php bin/console doctrine:migrations:latest
# 执行下一个迁移
php bin/console doctrine:migrations:execute App\Migrations\Version20230101000000 --up
# 撤销单个迁移
php bin/console doctrine:migrations:execute App\Migrations\Version20230101000000 --down

配置文件高级选项

# config/packages/doctrine_migrations.yaml
doctrine_migrations:
    table_storage:
        table_name: 'migration_versions'
        version_column_name: 'version'
        version_column_length: 1024
        executed_at_column_name: 'executed_at'
        execution_time_column_name: 'execution_time'
    # 组织迁移目录
    migrations_paths:
        'App\Migrations\App': '%kernel.project_dir%/migrations/app'
        'App\Migrations\Data': '%kernel.project_dir%/migrations/data'
    # 格式化
    organize_migrations: 'year_and_month'  # 或 'year'
    custom_template: '%kernel.project_dir%/migrations/template.tpl'

多环境配置

# config/packages/dev/doctrine_migrations.yaml
doctrine_migrations:
    # 开发环境自动生成迁移
    auto_generate: true
# config/packages/prod/doctrine_migrations.yaml
doctrine_migrations:
    # 生产环境禁用自动生成
    auto_generate: false

团队协作指南

# 1. 创建特性分支
git checkout -b feature/add-user-profile
# 2. 修改实体,生成迁移
php bin/console make:migration
# 3. 查看迁移内容
php bin/console doctrine:migrations:up-to-date
# 4. 合并到主分支前处理冲突
# 如果多个迁移有相同的时间戳,手动修改文件名
# 5. 在测试/生产环境执行
php bin/console doctrine:migrations:migrate --env=prod

常见问题与解决方案

// 问题1: 迁移文件已提交,但需要修改
// 解决:创建新的迁移文件,不要修改已提交的迁移
// 问题2: 迁移执行失败
public function up(Schema $schema): void
{
    try {
        // 迁移逻辑
    } catch (\Exception $e) {
        // 错误处理
        $this->write('迁移执行失败: ' . $e->getMessage());
    }
}
// 问题3: 数据迁移
public function up(Schema $schema): void
{
    // 先改表结构
    $this->addSql('ALTER TABLE users ADD COLUMN status VARCHAR(20)');
    // 再更新数据
    $this->addSql('UPDATE users SET status = :status', [
        'status' => 'active'
    ]);
}

监控与审计

# 查看迁移日志
php bin/console doctrine:migrations:status
php bin/console doctrine:migrations:latest
# 跟踪迁移执行时间
# 在 migration_versions 表中有 execution_time 字段

CI/CD 集成

# .gitlab-ci.yml 或 Jenkinsfile
deploy:
  script:
    - composer install --no-dev
    - php bin/console doctrine:migrations:migrate --no-interaction
    - php bin/console cache:clear
  1. 每次数据库变更都使用迁移,不要手动修改数据库
  2. 迁移文件要提交到版本控制,确保团队同步
  3. 每个迁移只做一件事,便于回滚和审计
  4. 始终提供 down() 方法,确保可回滚
  5. 在生产环境前测试迁移,避免数据丢失
  6. 使用事务确保数据一致性,复杂迁移可能需要关闭自动事务
  7. 数据库 schema 和代码版本要匹配,迁移执行前更新代码

这样就能确保数据库变更像代码变更一样可追踪、可回滚、可协作。

抱歉,评论功能暂时关闭!