Symfony Migration 与版本管理详解
基础概念
Symfony 的迁移系统(DoctrineMigrationsBundle)用于管理数据库 schema 的版本变更,类似于 Git 管理代码版本。

安装与配置
# 安装迁移包
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
- 每次数据库变更都使用迁移,不要手动修改数据库
- 迁移文件要提交到版本控制,确保团队同步
- 每个迁移只做一件事,便于回滚和审计
- 始终提供
down()方法,确保可回滚 - 在生产环境前测试迁移,避免数据丢失
- 使用事务确保数据一致性,复杂迁移可能需要关闭自动事务
- 数据库 schema 和代码版本要匹配,迁移执行前更新代码
这样就能确保数据库变更像代码变更一样可追踪、可回滚、可协作。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播