shipmonk / doctrine-two-phase-migrations
Doctrine ORM 的两阶段迁移:在部署新代码库版本前后
Requires
- php: ^8.1
- doctrine/dbal: ^3.6.0 || ^4.0.0
- doctrine/orm: ^3.0.0
- symfony/console: ^5.4.0 || ^6.0.0 || ^7.0.0
Requires (Dev)
- doctrine/annotations: ^2.0.0
- editorconfig-checker/editorconfig-checker: ^10.4.0
- ergebnis/composer-normalize: ^2.28
- phpstan/phpstan: ^1.11.5
- phpstan/phpstan-phpunit: ^1.4.0
- phpstan/phpstan-strict-rules: ^1.6.0
- phpunit/phpunit: ^10.5.29
- psr/log: ^1 || ^2 || ^3
- shipmonk/composer-dependency-analyser: ^1.0
- shipmonk/phpstan-rules: ^3.0.0
- slevomat/coding-standard: ^8.15.0
This package is auto-updated.
Last update: 2024-09-02 11:53:07 UTC
README
这个轻量级库允许你在集群环境(如 kubernetes)的部署过程中执行更安全的 Doctrine 迁移,其中 rolling-update 会发生。每个迁移有两个 up 阶段,没有 down 阶段。
- before
- 在任何流量到达新应用程序版本之前调用
- 通常包含 ADD COLUMN 等。
- after
- 在部署完成后且没有流量到达旧应用程序版本时调用
- 通常包含 DROP COLUMN 等。
您可以在 YouTube 上查看有关此库的捷克语演讲:Czech talk about this library on YouTube。
安装
composer require shipmonk/doctrine-two-phase-migrations
在 symfony 应用程序中的配置
如果您的 Doctrine\ORM\EntityManagerInterface
是自动注入的,只需在您的 DIC 中注册少量服务并标记命令即可
_instanceof: Symfony\Component\Console\Command\Command: tags: - console.command services: ShipMonk\Doctrine\Migration\Command\MigrationInitCommand: ShipMonk\Doctrine\Migration\Command\MigrationRunCommand: ShipMonk\Doctrine\Migration\Command\MigrationSkipCommand: ShipMonk\Doctrine\Migration\Command\MigrationCheckCommand: ShipMonk\Doctrine\Migration\Command\MigrationGenerateCommand: ShipMonk\Doctrine\Migration\MigrationService: ShipMonk\Doctrine\Migration\MigrationConfig: $migrationsDir: "%kernel.project_dir%/migrations" # more optional parameters: $migrationClassNamespace: 'YourCompany\Migrations' $migrationTableName: 'doctrine_migration' $migrationClassPrefix: 'Migration' # will be appended with date('YmDHis') by default $excludedTables: ['my_tmp_table'] # migration table ($migrationTableName) is always added to excluded tables automatically $templateFilePath: "%kernel.project_dir%/migrations/my-template.txt" # customizable according to your coding style $templateIndent: "\t\t" # defaults to spaces
命令
初始化
安装后,您需要在您的数据库中创建 migration
表。即使该表已被初始化,运行它也是安全的。
$ bin/console migration:init
# example output:
Creating migration table... done.
生成新迁移
您可以自动从数据库 <=> 实体差异生成迁移。这将所有由 Doctrine 生成的查询都放在“before”阶段,这对任何破坏性操作都是不正确的。请务必验证迁移并将查询移动到适当的阶段或调整它们。当没有检测到差异时,将生成空迁移类。
$ bin/console migration:generate
# example output:
Migration version 20230217063818 was generated
生成的文件看起来像这样
<?php declare(strict_types = 1); namespace App\Migrations; use ShipMonk\Doctrine\Migration\Migration; use ShipMonk\Doctrine\Migration\MigrationExecutor; class Migration20230217063818 implements Migration { public function before(MigrationExecutor $executor): void { $executor->executeQuery('CREATE INDEX IDX_542819F35080ECDE ON my_table (my_column)'); } public function after(MigrationExecutor $executor): void { } }
您可以通过向 MigrationConfig
提供 $templateFilePath
自定义模板来调整它,但它需要实现 Migration
接口。
状态验证
您可以检查等待迁移和实体同步状态
$ bin/console migration:check
# example success output:
Phase before fully executed, no awaiting migrations
Phase after fully executed, no awaiting migrations
Database is synced with entities, no migration needed.
$ bin/console migration:check # example failure output: Phase before fully executed, no awaiting migrations Phase after has executed migrations not present in /app/migrations: 20220208123456 Database is not synced with entities, missing updates: > DROP INDEX IDX_9DA1A2026EA0B6CA ON my_table
跳过所有迁移
您还可以将所有迁移标记为已执行,例如,当您仅从实体创建新鲜架构时。这将标记所有未执行的迁移在所有阶段已迁移。
$ bin/console migration:skip
# example output:
Migration 20230214154154 phase after skipped.
Migration 20230214155401 phase after skipped.
Migration 20230215050511 phase after skipped.
Migration 20230217061357 phase after skipped.
执行迁移
执行不会进行任何交互,如果没有迁移要执行,则不会失败或警告。
$ bin/console migration:run before # example output: Executing migration 20220224045126 phase before... done, 0.032 s elapsed. Executing migration 20220224081809 phase before... done, 0.019 s elapsed. Executing migration 20220224114846 phase before... done, 0.015 s elapsed. $ bin/console migration:run after # example output: Executing migration 20220224045126 phase after... done, 0.033 s elapsed. Executing migration 20220224081809 phase after... done, 0.006 s elapsed. Executing migration 20220224114846 phase after... done, 0.000 s elapsed.
在执行所有迁移(例如在测试环境中)时,您可能希望实现逐个执行。您可以通过
$ bin/console migration:run both
# example output:
Executing migration 20220224045126 phase before... done, 0.032 s elapsed.
Executing migration 20220224045126 phase after... done, 0.033 s elapsed.
Executing migration 20220224081809 phase before... done, 0.019 s elapsed.
Executing migration 20220224081809 phase after... done, 0.006 s elapsed.
高级用法
为每个执行的查询运行自定义代码
您可以通过实现 MigrationExecutor
接口并将实现注册为服务来挂钩迁移执行。实现 executeQuery()
以在每次查询之前/之后运行检查或其他代码。此方法接口模仿了 Doctrine\DBAL\Connection::executeQuery()
的接口。
在事务中运行所有查询
您可以将模板(或单个迁移)更改为扩展; TransactionalMigration
。这会导致每个阶段都在迁移中执行。请注意,许多数据库(如 MySQL)不支持 DDL 操作(ALTER 等)的事务。
检查执行持续时间
迁移表有 started_at
和 finished_at
列,包含带有微秒的 datetime 数据。但是,这些列默认声明为 VARCHAR,因为 doctrine/dbal 还不支持微秒。这可能使 datetime 操作(如持续时间计算)复杂化。您可以在某些迁移中手动调整结构以满足您的需求(例如,对于 MySQL 使用 DATETIME(6)
)。
+----------------+--------+-----------------------------+---------------------------+
| version | phase | started_at | finished_at |
+----------------+--------+-----------------------------+---------------------------+
| 20220224045126 | before | 2023-02-17 05:19:50.225048 | 2023-02-17 05:19:50.672871 |
| 20220224045126 | after | 2023-02-17 05:23:11.265727 | 2023-02-17 05:23:11.982982 |
+------------------------------------------------------+----------------------------+
与 doctrine/migrations 的区别
底层的差异检查和生成与doctrine/migrations中的操作相同,因为它使用了doctrine/dbal的特性。主要区别是我们不提供任何降级阶段。
这个库旨在提供在滚动更新部署中安全迁移所需的内核功能。基本上所有逻辑都在MigrationService
中,它只有大约300行代码。我们试图使其尽可能轻量,不计划从doctrine/migrations复制功能。