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