大家好,欢迎来到今天的“数据库迁移、Schema演进与零宕机部署”分享会。今天咱们不讲那些云里雾里的理论,就来点实在的,手把手教你如何在PHP项目里优雅地折腾数据库,保证业务不掉链子。
数据库迁移:从“手动挡”到“自动挡”
话说当年,我们改数据库结构,那叫一个胆战心惊。手动执行SQL,生怕一不小心把数据给删了。后来有了数据库迁移工具,简直是救星!
什么是数据库迁移?
简单来说,数据库迁移就是用代码来描述数据库结构的变更。你可以把每次修改都记录在一个文件里,然后按照顺序执行这些文件,就能把数据库升级到最新的状态。
为什么要用数据库迁移?
- 版本控制: 就像代码一样,数据库结构也能版本控制。方便回滚,方便团队协作。
- 自动化部署: 部署的时候,一键执行迁移,省时省力。
- 避免人为错误: 手动执行SQL容易出错,迁移工具可以保证一致性。
PHP里有哪些好用的迁移工具?
- Laravel Migration: 如果你用Laravel框架,那自带的Migration功能简直不要太香。
- Doctrine Migration: Doctrine ORM也提供了Migration功能,适合用Doctrine的项目。
- Phinx: 一个独立的PHP迁移工具,可以和任何框架一起使用。
实战演练:用Phinx搞定数据库迁移
-
安装Phinx:
composer require robmorgan/phinx
-
初始化Phinx:
./vendor/bin/phinx init
这个命令会在你的项目根目录下创建一个
phinx.php
配置文件,以及一个db/migrations
目录,用来存放迁移文件。 -
配置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' ];
-
创建迁移文件:
./vendor/bin/phinx create CreateUsersTable
这个命令会在
db/migrations
目录下创建一个名为CreateUsersTable
的迁移文件。 -
编写迁移代码:
打开刚刚创建的迁移文件,编写你的数据库结构变更代码。
<?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
的表,包含username
、email
、password
等字段。 -
执行迁移:
./vendor/bin/phinx migrate -e development
这个命令会执行所有未执行的迁移文件,把你的数据库结构更新到最新的状态。
-e development
表示在development环境下执行迁移。 -
回滚迁移:
./vendor/bin/phinx rollback -e development
这个命令会回滚上一次执行的迁移文件,把你的数据库结构恢复到之前的状态。
小贴士:
- 尽量使用
change()
方法,Phinx会自动生成回滚代码。 - 如果要执行复杂的SQL语句,可以使用
execute()
方法。 - 迁移文件要保持幂等性,即多次执行的结果应该是一样的。
Schema演进:让数据库结构跟上业务的脚步
业务发展太快,数据库结构也要跟着变。但是,如果直接修改线上数据库,很容易出问题。所以,我们需要一套优雅的Schema演进方案。
什么是Schema演进?
Schema演进是指在不影响现有业务的情况下,逐步修改数据库结构的过程。
Schema演进的挑战:
- 兼容性: 新旧代码要能同时访问数据库。
- 数据迁移: 有时候需要把旧数据迁移到新的结构。
- 风险控制: 避免因为Schema变更导致业务故障。
Schema演进的策略:
- 渐进式修改: 不要一次性修改太多,每次只改一点点。
- 向后兼容: 新代码要能兼容旧的数据库结构。
- 向前兼容: 旧代码要能兼容新的数据库结构。
- 灰度发布: 先在一小部分服务器上部署新代码,观察一段时间,没有问题再全量发布。
实战演练:添加一个is_active
字段
假设我们要给users
表添加一个is_active
字段,用来表示用户是否激活。
-
添加字段:
创建一个新的迁移文件,添加
is_active
字段。<?php use PhinxMigrationAbstractMigration; class AddIsActiveToUsers extends AbstractMigration { public function change() { $table = $this->table('users'); $table->addColumn('is_active', 'boolean', ['default' => false]) ->update(); } }
-
发布新代码:
部署包含新字段的代码。但是,旧代码仍然可以正常运行,因为旧代码不需要用到
is_active
字段。 -
数据迁移:
如果需要,可以编写一个数据迁移脚本,把旧数据的
is_active
字段设置为默认值。 -
删除旧代码:
过一段时间,确认所有代码都更新到最新版本后,可以删除旧代码。
Schema演进的常见模式:
模式 | 描述 |
---|---|
读写分离 | |
影子表 | |
字段拆分 | |
字段合并 | |
表拆分 | 把一个表拆分成多个表,例如把users 表拆分成users 和user_profiles 。 |