使用模式构建:模式版本控制模式(The Schema Versioning Pattern)

有一种说法,生命中唯一不变的东西就是变化。这同样适用于数据库模式。我们会想要获取我们曾经认为不需要的信息。或者一些新上线的服务需要包含在数据库记录中。不管变更背后的原因是什么,一段时间之后,我们不可避免地需要对应用程序中的底层模式设计进行更改。虽然这经常会在传统的表格数据库系统中带来一些挑战甚至是麻烦,但在MongoDB中,我们可以使用模式版本控制来简化这一过程。

如前所述,在一个表格式数据库中更新数据模式是很有挑战性的。通常需要停止应用程序,迁移数据库以支持新模式,然后重新启动。这种停机时间会导致糟糕的用户体验。此外,如果迁移没有完全成功,会发生什么?恢复到先前的状态通常是一个更大的挑战。

在MongoDB中,存在于同一数据库集合中的文档可以有不同的形式,模式版本控制模式利用了这一特性。MongoDB的这种多态性非常强大,它允许具有不同字段甚至不同类型的同一字段这样的文档同时存在。

模式版本控制模式

这一模式的实现相对容易。我们的应用程序最初会使用一种模式,而这个模式最终会需要修改。当这种情况发生时,我们可以使用schema_version字段创建新模式并将其保存到数据库中。这个字段允许我们的应用程序知道如何处理这个特定的文档。或者,我们可以让应用程序根据某些给定字段的存在或不存在来推断版本,但最好还是使用前一种方法。我们可以假定没有此字段的文档是版本1,然后每个新的模式版本都会增加schema_version字段的值,并可以在应用程序中进行相应的处理。

当保存新信息时,我们使用最新的模式版本。我们可以根据应用程序和使用场景来决定是否需要将所有文档更新为新设计,或是在访问时再更新,又或者根本不进行更新。在应用程序内部,我们会为每个模式版本创建相应的处理函数。

应用场景示例

如前所述,几乎每个数据库在其生命周期中的某个时刻都会产生变更,因此这个模式在许多情况下都非常有用。让我们来看一个客户档案的例子。我们从前就开始保存客户信息,那时还没有这么多的联系方式,要找一个人只能在他在家或者工作的时候:

{
    "_id": "",
    "name": "Anakin Skywalker",
    "home": "503-555-0000",
    "work": "503-555-0010"
}

随着时间的推移,越来越多的客户记录被保存起来,有一天我们发现手机号码也是需要保存的。可以很容易地添加这一字段。

{
    "_id": "",
    "name": "Darth Vader",
    "home": "503-555-0100",
    "work": "503-555-0110",
    "mobile": "503-555-0120"
}

又过了一段时间,我们发现越来越少的人拥有家庭电话,而其它的联系方式正变得越来越重要。像Twitter、Skype和Google Hangouts这样的东西正变得越来越流行,这些甚至在我们第一次相互保存联系信息时可能都还不存在。我们还希望尽可能地使我们的应用程序具有前瞻性。在阅读了使用模式构建系列文章之后,我们了解了属性模式,并将其实现到一个contact_method数组中。为此,我们创建了一个新的模式版本。

{
    "_id": "",
    "schema_version": "2",
    "name": "Anakin Skywalker (Retired)",
    "contact_method": [
        { "work": "503-555-0210" },
        { "mobile": "503-555-0220" },
        { "twitter": "@anakinskywalker" },
        { "skype": "AlwaysWithYou" }
    ]
}

MongoDB文档模型的灵活性允许在数据库不停机的情况下进行所有这些操作。从应用的角度来看,可以设计成同时读取模式的两个版本。即使涉及的应用服务器不止一个,应用程序对于如何处理模式差异的更改也是不需要停机的。

结论

模式版本控制非常适合于这样的情况:不允许应用程序停机、更新文档可能需要数小时、数天或数周才能完成、不需要将文档更新到新版本,也不是这些要求的组合。它可以轻松添加新的schema_version字段,并允许应用程序根据这些更改进行调整。此外,它还为我们开发人员提供了更好地决定何时以及如何进行数据迁移的机会。所有这些都会帮助减少未来的技术债务,这是这个模式的另一大优势。

与本系列中提到的其它模式一样,使用模式版本控制模式也需要一些考量。如果文档中某个字段的索引不在同一级别,则在迁移文档时可能需要2个索引。

这种模式的主要好处之一是数据模型本身的简单性。只需添加schema_version字段,然后允许应用程序处理不同的文档版本。

此外,正如应用场景示例中所看到的,我们可以将设计模式组合在一起以获得额外的性能提升。在本例中,将模式版本控制和属性模式一起使用,允许在不停机的情况下进行模式升级,这使得模式版本控制这一模式在MongoDB中特别强大。这很可能为你提供了一个充分的理由,让你在应用程序中使用MongoDB的文档模型而不是老式的表格数据库。

本系列的下一篇文章将总结我们迄今为止介绍的所有模式,并提供一些我们发现特别适合于每个模式的场景示例附加信息。

如果你有任何问题,请在下面留言。

使用模式构建系列:

本文译自:Building with Patterns: The Document Versioning Pattern

2 thoughts on “使用模式构建:模式版本控制模式(The Schema Versioning Pattern)

Leave a Reply