PHP `Database Migration` `Schema Evolution` 与 `Zero-Downtime Deployment`

大家好,欢迎来到今天的“数据库迁移、Schema演进与零宕机部署”分享会。今天咱们不讲那些云里雾里的理论,就来点实在的,手把手教你如何在PHP项目里优雅地折腾数据库,保证业务不掉链子。

数据库迁移:从“手动挡”到“自动挡”

话说当年,我们改数据库结构,那叫一个胆战心惊。手动执行SQL,生怕一不小心把数据给删了。后来有了数据库迁移工具,简直是救星!

什么是数据库迁移?

简单来说,数据库迁移就是用代码来描述数据库结构的变更。你可以把每次修改都记录在一个文件里,然后按照顺序执行这些文件,就能把数据库升级到最新的状态。

为什么要用数据库迁移?

  • 版本控制: 就像代码一样,数据库结构也能版本控制。方便回滚,方便团队协作。
  • 自动化部署: 部署的时候,一键执行迁移,省时省力。
  • 避免人为错误: 手动执行SQL容易出错,迁移工具可以保证一致性。

PHP里有哪些好用的迁移工具?

  • Laravel Migration: 如果你用Laravel框架,那自带的Migration功能简直不要太香。
  • Doctrine Migration: Doctrine ORM也提供了Migration功能,适合用Doctrine的项目。
  • Phinx: 一个独立的PHP迁移工具,可以和任何框架一起使用。

实战演练:用Phinx搞定数据库迁移

  1. 安装Phinx:

    composer require robmorgan/phinx
  2. 初始化Phinx:

    ./vendor/bin/phinx init

    这个命令会在你的项目根目录下创建一个phinx.php配置文件,以及一个db/migrations目录,用来存放迁移文件。

  3. 配置Phinx:

    打开phinx.php,配置你的数据库连接信息。

    <?php
    
    return
    [
        'paths' => [
            'migrations' => '%%PHINX_CONFIG_DIR%%/db/migrations',
            'seeds' => '%%PHINX_CONFIG_DIR%%/db/seeds'
        ],
        'environments' => [
            'default_migration_table' => 'phinxlog',
            'default_environment' => 'development',
            'production' => [
                'adapter' => 'mysql',
                'host' => 'localhost',
                'name' => 'production_db',
                'user' => 'root',
                'pass' => 'secret',
                'port' => '3306',
                'charset' => 'utf8',
            ],
            'development' => [
                'adapter' => 'mysql',
                'host' => 'localhost',
                'name' => 'development_db',
                'user' => 'root',
                'pass' => 'secret',
                'port' => '3306',
                'charset' => 'utf8',
            ],
            'testing' => [
                'adapter' => 'mysql',
                'host' => 'localhost',
                'name' => 'testing_db',
                'user' => 'root',
                'pass' => 'secret',
                'port' => '3306',
                'charset' => 'utf8',
            ]
        ],
        'version_order' => 'creation'
    ];
  4. 创建迁移文件:

    ./vendor/bin/phinx create CreateUsersTable

    这个命令会在db/migrations目录下创建一个名为CreateUsersTable的迁移文件。

  5. 编写迁移代码:

    打开刚刚创建的迁移文件,编写你的数据库结构变更代码。

    <?php
    
    use PhinxMigrationAbstractMigration;
    
    class CreateUsersTable extends AbstractMigration
    {
        /**
         * Change Method.
         *
         * Write your reversible migrations using this method.
         *
         * More information on writing migrations is available here:
         * http://docs.phinx.org/en/latest/migrations.html#the-change-method
         *
         * Remember to call "create()" or "update()" and NOT "save()" when working
         * with the Table class.
         */
        public function change()
        {
            $table = $this->table('users');
            $table->addColumn('username', 'string', ['limit' => 255])
                  ->addColumn('email', 'string', ['limit' => 255])
                  ->addColumn('password', 'string', ['limit' => 255])
                  ->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
                  ->addColumn('updated_at', 'timestamp', ['null' => true, 'default' => null])
                  ->create();
        }
    }

    这个例子创建了一个名为users的表,包含usernameemailpassword等字段。

  6. 执行迁移:

    ./vendor/bin/phinx migrate -e development

    这个命令会执行所有未执行的迁移文件,把你的数据库结构更新到最新的状态。-e development表示在development环境下执行迁移。

  7. 回滚迁移:

    ./vendor/bin/phinx rollback -e development

    这个命令会回滚上一次执行的迁移文件,把你的数据库结构恢复到之前的状态。

小贴士:

  • 尽量使用change()方法,Phinx会自动生成回滚代码。
  • 如果要执行复杂的SQL语句,可以使用execute()方法。
  • 迁移文件要保持幂等性,即多次执行的结果应该是一样的。

Schema演进:让数据库结构跟上业务的脚步

业务发展太快,数据库结构也要跟着变。但是,如果直接修改线上数据库,很容易出问题。所以,我们需要一套优雅的Schema演进方案。

什么是Schema演进?

Schema演进是指在不影响现有业务的情况下,逐步修改数据库结构的过程。

Schema演进的挑战:

  • 兼容性: 新旧代码要能同时访问数据库。
  • 数据迁移: 有时候需要把旧数据迁移到新的结构。
  • 风险控制: 避免因为Schema变更导致业务故障。

Schema演进的策略:

  • 渐进式修改: 不要一次性修改太多,每次只改一点点。
  • 向后兼容: 新代码要能兼容旧的数据库结构。
  • 向前兼容: 旧代码要能兼容新的数据库结构。
  • 灰度发布: 先在一小部分服务器上部署新代码,观察一段时间,没有问题再全量发布。

实战演练:添加一个is_active字段

假设我们要给users表添加一个is_active字段,用来表示用户是否激活。

  1. 添加字段:

    创建一个新的迁移文件,添加is_active字段。

    <?php
    
    use PhinxMigrationAbstractMigration;
    
    class AddIsActiveToUsers extends AbstractMigration
    {
        public function change()
        {
            $table = $this->table('users');
            $table->addColumn('is_active', 'boolean', ['default' => false])
                  ->update();
        }
    }
  2. 发布新代码:

    部署包含新字段的代码。但是,旧代码仍然可以正常运行,因为旧代码不需要用到is_active字段。

  3. 数据迁移:

    如果需要,可以编写一个数据迁移脚本,把旧数据的is_active字段设置为默认值。

  4. 删除旧代码:

    过一段时间,确认所有代码都更新到最新版本后,可以删除旧代码。

Schema演进的常见模式:

模式 描述
读写分离
影子表
字段拆分
字段合并
表拆分 把一个表拆分成多个表,例如把users表拆分成usersuser_profiles

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注