简介
数据库架构定义了关系型数据库管理的数据的结构和相互关系。虽然在项目开始时开发一个深思熟虑的架构很重要,但不断变化的需求使得对初始架构的更改难以或无法避免。由于架构管理着数据的形状和边界,因此必须仔细应用更改,以符合使用它的应用程序的预期,并避免丢失数据库系统当前保存的数据。
在本文中,我们将介绍什么是数据库架构迁移、它们解决了哪些问题以及不同的实现策略。我们将探讨它们解决的各种痛点以及它们可能带来的一些潜在陷阱。
什么是数据库迁移?
数据库迁移,也称为架构迁移、数据库架构迁移或简称迁移,是为了修改关系型数据库中对象的结构而开发的一组受控变更。迁移有助于将数据库架构从当前状态转换为新的期望状态,无论是添加表和列、删除元素、拆分字段,还是更改类型和约束。
迁移以编程方式管理数据结构的增量(通常是可逆的)变更。数据库迁移软件的目标是使数据库变更可重复、可共享和可测试,而不会丢失数据。通常,迁移软件会生成描述将数据库从已知状态转换为新状态所需的确切操作集的工件。这些工件可以提交到并由常规版本控制软件管理,以跟踪变更并在团队成员之间共享。
尽管防止数据丢失通常是迁移软件的目标之一,但删除或破坏性修改当前存储数据的结构的变更可能会导致数据删除。为了应对这种情况,迁移通常是一个受监督的过程,包括检查生成的变更脚本并进行任何必要的修改以保留重要信息。
迁移工具有哪些优点?
迁移很有帮助,因为它们允许数据库架构随需求变化而演进。它们帮助开发人员规划、验证并安全地将架构更改应用于其环境。这些划分的更改以精细的粒度定义,并描述了在数据库的各种“版本”之间移动时必须发生的转换。
通常,迁移系统会创建可以共享、应用于多个数据库系统并存储在版本控制中的工件或文件。这有助于构建数据库修改历史,该历史可以与客户端应用程序中的伴随代码更改紧密关联。数据库架构和应用程序对该结构的假设可以同步演进。
其他一些好处包括允许(有时是要求)通过将操作列表的生成与它们的执行分离来手动调整过程。每个更改都可以进行审计、测试和修改,以确保获得正确的结果,同时仍然依赖自动化来完成大部分过程。
迁移工具有哪些缺点?
迁移系统并非没有缺陷,但幸运的是,大多数缺陷都可以通过流程和监督来缓解。
由于迁移会修改现有数据库结构,因此必须小心避免数据丢失。这可能是由工具做出的不正确假设或需要理解数据结构背后含义的转换所致。尽管可能很容易假定生成的迁移文件是正确的,但由于迁移文件主要关注数据结构,因此您有责任确保数据也得到正确保留或转换。
如果迁移应用于处于与预期不同状态的数据库,也可能会出错。例如,当在迁移系统范围之外对数据库结构进行更改或以错误的顺序应用迁移时,可能会发生这种情况。所有迁移系统都依赖于理解数据库的当前状态来正确修改现有结构。如果实际状态偏离了预期状态,迁移可能会失败或以不希望的方式更改数据库。
迁移的另一个潜在问题是它们通常与工具高度相关。迁移系统生成表示数据库状态或所需更改的工件。尽管有些工具以纯 SQL 格式生成结果,但它们有时会在注释中编码供工具解析的额外详细信息,或者可能使用特殊的文件名格式来指示顺序。在迁移工具之间切换可能很困难,除非在前一代和当前一代的迁移文件之间进行干净的断开。
基于状态的迁移 vs 基于变更的迁移
迁移软件采用两种主要的架构转换策略:基于状态的迁移和基于变更的迁移。两者都可以有效地管理流程,有时,结合使用两者会很有帮助。然而,每种方法的优点通常决定了哪种方法最适合项目,这取决于它与所涉及团队的开发风格的匹配程度。
基于状态的迁移
基于状态的迁移软件创建描述如何从头开始重新创建所需数据库状态的工件。它生成的文件可以应用于空的关关系型数据库系统,使其完全更新。
在创建描述所需状态的工件后,实际的迁移涉及将生成的文件与数据库的当前状态进行比较。此过程允许软件分析两种状态之间的差异,并生成一个或多个新文件,使当前数据库架构与文件描述的架构保持一致。然后将这些变更操作应用于数据库以达到目标状态。
基于状态的迁移需要注意什么
与几乎所有迁移一样,基于状态的迁移文件必须由经验丰富的开发人员仔细检查以监督整个过程。描述所需最终状态的文件和概述使当前数据库符合要求所需操作的文件都必须经过审查,以确保转换不会导致数据丢失。例如,如果生成的操操作试图通过删除当前表并以新名称重新创建它来重命名表,则知识渊博的人必须识别这一点并进行干预以防止数据丢失。
如果数据库架构经常发生需要此类手动干预的重大更改,基于状态的迁移可能会显得相当笨拙。由于这种开销,此技术通常更适合于架构提前经过深思熟虑且基本更改不经常发生的场景。
然而,基于状态的迁移确实具有生成在一个上下文中完整描述数据库状态的文件的优点。这有助于新开发人员更快上手,并且与版本控制系统中的工作流配合良好,因为代码分支引入的冲突更改可以轻松解决。
基于变更的迁移
基于状态的迁移的主要替代方案是基于变更的迁移系统。基于变更的迁移也生成文件,这些文件改变数据库中的现有结构以达到所需状态。这种方法不是发现所需数据库状态与当前状态之间的差异,而是基于已知数据库状态来定义将其带入新状态的操作。连续生成迁移文件以进一步修改数据库,从而创建一系列变更文件,这些文件在连续应用时可以重现最终数据库状态。
由于基于变更的迁移通过概述从已知数据库状态到所需状态所需的操作来工作,因此从初始起点开始需要一个不间断的迁移文件链。该系统需要一个初始状态(可以是空数据库系统或描述起始结构的文件)、描述使架构经历每个转换操作的文件以及必须应用迁移文件的定义顺序。
基于变更的迁移需要注意什么
基于变更的迁移通过其创建的一系列转换脚本,追溯数据库架构设计的来源到原始结构。这有助于说明数据库结构演变,但对于理解数据库在任何一个时间点的完整状态帮助不大,因为每个文件中描述的更改都会修改上一个迁移文件生成的结构。
由于先前的状态对于基于变更的系统非常重要,因此系统通常在数据库系统本身内部使用一个数据库来跟踪已应用了哪些迁移文件。这有助于软件了解系统当前所处的状态,而无需分析当前结构并将其与所需状态进行比较(所需状态只能通过编译整个迁移文件系列才能得知)。
这种方法的缺点是,在初始点之后,数据库的当前状态并没有在代码库中描述。每个迁移文件都是基于上一个文件构建的,因此虽然更改被很好地划分开来,但任何一个时间点的整个数据库状态都更难以推断。此外,由于操作顺序非常重要,解决开发人员做出冲突更改所产生的冲突可能会更加困难。
然而,基于变更的系统确实具有允许对数据库结构进行快速迭代更改的优点。与耗时的分析数据库当前状态、将其与所需状态进行比较、创建文件以执行必要操作并将其应用于数据库的过程不同,基于变更的系统根据先前的更改来假定数据库的当前状态。这通常使更改更轻量级,但确实使带外对数据库的更改特别危险,因为迁移可能使目标系统处于未定义状态。
如何使用数据库迁移?
现在我们已经介绍了两种主要的迁移系统类别,接下来让我们看看在应用程序开发、部署和协作过程中如何实际使用这些工具。
开发阶段
从您第一次修改初始数据架构的那一刻起,数据库迁移就可能变得相关。实际上,大多数迁移工具都会生成迁移文件,以将关系型数据库从完全空的状态带到初始架构。
随着您开发应用程序,您希望存储的数据形状、数据库系统的要求以及您希望保留的特定详细信息通常会发生变化。这可能发生在您更全面地理解问题空间时,或者当附加功能需要额外数据或当前信息的不同布局时。在开发过程中定义这些架构更改很重要,以确保工件与相关代码同步并部署。
将迁移文件与相关代码库一起存储和管理,使得数据库架构更改可以经历与代码更改相同的审查过程。如前所述,基于状态的迁移可以使此过程更容易,因为通过文件差异即可发现期望状态之间的冲突。基于变更的系统在发生冲突时需要更仔细和手动解决,因为顺序很重要,并且在任何迭代迁移文件中都无法看到整个数据结构。
一般来说,在开发中定义数据库更改时最好采取保守态度,并记住您的更改最终可能会针对生产数据运行。这对于破坏性更改尤为重要。应考虑删除的更安全选项,例如重命名列而不是删除它们,通过取消发布数据而不是删除数据来执行“软”删除,或者在转换数据时复制数据结构而不是覆盖它。
换句话说,数据库架构迁移是您将与代码更改一起维护的更改之一。架构迁移通常应与代码更改同时考虑,以确保所有更改都已文档化并适用于当前的数据库设计。
测试和部署阶段
一旦您的迁移创建完成,您通常会在日益重要的环境中部署它们,以确保它们按预期工作,并且满足您的所有代码要求。虽然您可能在开发环境中开发和应用了迁移,但您可能需要在具有更真实数据、集成和负载的其他环境中对其进行测试,就像您对代码更改所做的那样。
此时,您需要确保迁移文件干净地应用于目标数据库,初始目标状态与您在开发迁移文件时的结构和假设一致,并且数据库中保存的数据不会受到您正在进行的更改的负面影响。可以执行手动和自动化检查的组合以确认满足这些要求。
一旦更改在暂存环境中被验证为安全和功能正常,它们就可以应用于生产数据库系统。在将迁移应用于生产系统之前,如果当前没有最新副本,则务必考虑对当前数据进行完整备份。如果迁移出现不可预见的后果,或者暂存环境和生产环境之间的差异导致数据丢失,备份至关重要。
如何选择最佳迁移工具
鉴于我们目前涵盖的所有信息,您究竟如何决定最适合您项目的迁移解决方案?有许多不同的考量因素可以帮助您缩小最佳选择的范围。
有时,您使用的代码库语言、开发框架或数据库后端会强烈建议您用于管理迁移的工具。例如,虽然通常不是硬性要求,但许多 Web 框架都包含自己的迁移系统,用于管理其支持数据库的架构。这些系统通常与框架其余工具集成良好,有助于减少将数据库更改作为单独进程管理的摩擦。
另一个可能影响您选择的因素是给定工具的成熟度级别和提供的支持量。如前所述,各种工具生成的迁移文件往往彼此不直接兼容,尽管它们可以直接作为纯 SQL 应用。选择一个稳定的选项可以帮助您避免工具被废弃且不再维护的情况,从而迫使您在开发过程中途更改迁移流程。
您可能需要考虑的另一个要点是实际迁移工件的格式。如果它们是格式良好且组织良好的 SQL 文件,您可能可以依赖于能够理解这些文件产生的更改。同样,如果迁移是用项目其余部分使用的编程语言编写的,那么其含义通常易于解析,并且与其他开发任务相比,上下文切换较少。避免使用生成难以理解或手动修改的迁移文件的工具。
您的决策中的另一个因素可能涉及迁移系统提供的额外功能。某些工具提供了与其他工具的良好集成,或者提供了灵活的选项,例如将先前的基于变更的迁移文件压缩为“检查点”状态文件的能力。工具在检查迁移失败或在出现问题时回滚更改方面支持程度各不相同。您的需求和开发理念可能会影响您需要哪些功能。
结论
在本文中,我们探讨了数据库架构迁移的概念,并讨论了一些用于管理数据结构更改的策略。我们讨论了为什么迁移很有帮助,不同类别的迁移系统,以及每种方法提供的一些优势。最后,我们讨论了如何将迁移实际融入您的开发工作流程,以及如何找到最符合您风格和需求的工具。
总的来说,虽然架构迁移工具是可选的,但它们提供的组织、功能和控制使其成为开发中最广泛使用的数据库工具之一。能够规划和执行数据库结构更改并将这些修改与您的其余代码一起记录下来,这是非常有价值的。尽管迁移工具在它们提供的功能或用于分析差异和应用更改的策略上可能有所不同,但它们所扮演的角色是可靠和可预测开发的重要组成部分。
要使用 Prisma 执行迁移,您可以使用 Prisma Migrate。Prisma Migrate 根据声明式 Prisma 架构生成迁移文件,并将其应用于您的数据库。