问题的背景
在大型项目中,数据库结构的演变需要与应用程序代码平行进行。没有计划好的模式版本控制(对表、索引、键的添加、删除和修改)团队很快会失去同步,增加了丢失更改的风险,迁移失败的风险,并且回滚或重现错误变得更加复杂。
问题
传统的方法是通过 SQL 脚本手动更改数据库,这会导致更改执行的隐性顺序,回滚困难,环境(开发、测试、生产)之间版本不一致。没有通用的存储迁移的工具,很难了解谁在何时何因更改了模式。
解决方案
为此,使用模式迁移系统和数据库版本控制实践。应用工具(例如 Liquibase、Flyway、Alembic 适用于不同的数据库)可以将模式更改的 SQL 脚本直接存储在版本控制系统(git)中,形成严格的迁移顺序,并自动化所有环境中的模式更新。
代码示例(通过 Flyway 进行迁移):
-- V002__add_column_email.sql ALTER TABLE users ADD COLUMN email VARCHAR(255) NOT NULL;
Flyway 集成示例(例如,针对 Java):
Flyway.configure().dataSource(url, user, pass).load().migrate();
主要特点:
可以存储模式的“初始状态”(snapshot)而不是迁移吗? 乍看之下,整个模式的“转储”比迁移简单。但这会导致回滚、恢复中间状态和合并来自不同分支的更改的问题。迁移允许按顺序应用仅新的更改,并按需顺序进行。
是否需要在不同环境之间手动同步迁移? 不,现代系统尊重版本控制,自动只应用数据库中尚不存在的迁移。关键是,自动化在部署时应用迁移,而不是手动同步。
仅有 SQL 脚本迁移是否足够,还是还需存储其他内容? 良好的实践是除了 sql 脚本外,还存储其描述(目的、作者、日期)以及新的结构变化的验证器测试,以自动化迁移质量的控制。
项目使用普通的模式转储和开发人员的“手动”应用更改。更新启动后,客户发现生产数据库中没有部分新列,并且每次尝试更新模式时部分索引都会重复。
优点:
对于非常小的项目来说很快。
缺点:
支持困难;无法了解究竟是谁和做了什么更改;无法回滚;不同环境之间不一致。
团队集成了 Flyway,所有结构更改都通过带有代码审查的迁移来完成,任何版本的回滚只需几分钟,在所有环境中轻松进行测试和控制。
优点:
自动化、历史记录、部署时发生错误的可能性较小。
缺点:
需要稍微花时间记录每个结构的更改。