我正在阅读这个博客,我对所写的 5 篇文章有疑问。据我了解,您在包含所有 SQL DDL 语句的大型基线脚本上创建。完成此操作后,您可以在单独的脚本中跟踪每个更改。
但是我不明白脚本文件的名称如何与您的应用程序的特定构建相关联?他说,如果用户报告 3.1.5.6723 中的错误,您可以将脚本重新运行到该版本。你会在自己的文件中跟踪对表等的更改,还是在同一个脚本文件中进行所有 DLL 更改,然后按照他的说法在自己的文件中拥有视图等?
我正在阅读这个博客,我对所写的 5 篇文章有疑问。据我了解,您在包含所有 SQL DDL 语句的大型基线脚本上创建。完成此操作后,您可以在单独的脚本中跟踪每个更改。
但是我不明白脚本文件的名称如何与您的应用程序的特定构建相关联?他说,如果用户报告 3.1.5.6723 中的错误,您可以将脚本重新运行到该版本。你会在自己的文件中跟踪对表等的更改,还是在同一个脚本文件中进行所有 DLL 更改,然后按照他的说法在自己的文件中拥有视图等?
首先,数据库升级是邪恶的,但该博客描述了一场彻头彻尾的噩梦。
可以根据升级方法创建程序员能力矩阵:
我将描述所有技术问题,但在此之前让我声明以下内容(请原谅我的回答很长):
0 级和 1 级 这两种情况都是明显而愚蠢的。任何人都应该避免这种情况。
2 级 更改对于小桌子来说并没有那么糟糕,但对于大桌子来说可能是个问题。在非常大的表 (>1Gb) 上,完成 ALTER TABLE 可能需要几个小时甚至几天。此外,它确实只解决了模式升级问题,但存储数据呢?我还建议考虑物理数据布局,以了解这种方法背后的实际障碍。整个过程可能不安全,因此请确保您有备份。
解决方案:
级别 3 架构升级的问题通过将架构移到更高层来解决。无模式解决方案有些有限,主要是因为它禁用了关系模型背后的全部功能。可以提出一种混合方法,以同时具有快速升级和使用关系代数的能力。有一些有趣的文章:
请注意,升级过程的复杂性仍然存在,只是转移到了应用程序级别。有许多相关的场景,但我将描述一个我已经使用了几年的混合系统。我可以将数据模型描述为“具有关系的实体”。实体之间的关系在数据库级别表示,实体本身存储为 XML blob。
这个系统很成熟,有足够多的客户。有很多功能请求,所以研发和 QA 团队有点压力。最初的升级过程是作为一个独立的 Java 应用程序实现的,它从 DB 中读取 XML blob,使用 DOM API 对其进行升级并将其写回 DB。实际的方法看起来很简单,但背后有几个隐藏的问题:
我试图通过使用更严格的升级程序定义、验证规则和 CI 系统针对真实数据(收集所有客户)执行的广泛测试来降低所有潜在风险。由于旧升级脚本很久以前引入的旧问题,我很惊讶地看到一些步骤失败。为了解决隐藏的问题,开发了单独的升级步骤。还进行了一些优化以将升级时间减少到合理的 20-30 分钟。基于控制台的进度条实现完成了剩下的工作。
快速说明:任何最终用户都渴望看到任何长时间运行(> 2 分钟)操作的进展。请不要忘记实现这样的“乐趣”。
最初 DB 版本存储在单独的表中。请不要使用这种方法,因为单独对实体进行版本化并避免在升级期间锁定整个数据库会更好。
将显示一个升级过程作为示例(所有验证和验证步骤都隐藏在处理逻辑后面<build/>
)<version/>
。'-' 表示更少,'*' - 任何构建
<?xml version="1.0"?>
<upgrade>
<version name="-7.4">
<build name="*">
<script class="upgrade.version7.Replace...Script"/>
<script class="upgrade.version7.Update...Script"/>
<!-- 5 scripts skipped -->
</build>
</version>
<version name="-7.6">
<build name="*">
<script class="core.DatabaseUpdateVersion" version="7.6.48"/>
</build>
</version>
<version name="7.6">
<build name="*">
<script class="upgrade.version7.Update...Script"/>
<script class="core.DatabaseUpdateVersion" version="8.0.40"/>
<!-- 7 scripts skipped -->
</build>
</version>
<version name="8.0">
<build name="-53">... </build>
<build name="+52">... </build>
</version>
<version name="8.1">
<build name="-8"> ... </build>
<build name="-9">...</build>
<build name="-26">...</build>
<build name="-40">...</build>
<build name="-45">...</build>
<build name="-56">...</build>
<build name="-61">...</build>
<build name="-63">...</build>
<build name="-64">...</build>
<build name="-68">...</build>
<build name="-69">...</build>
<build name="-77">...</build>
<build name="-79">...</build>
<build name="-80">...</build>
<build name="-86">...</build>
<build name="-88">...</build>
<build name="-89"> ... </build>
</version>
<version name="8.2">...</version>
</upgrade>
每个脚本都是一个小型 Java 或 Groovy 实现(也使用了 XSLT)。后来还开发了降级程序,但这是完全不同的故事。
应用层的4 级 数据方案允许做很多有趣的事情。例如,可以用protobuf替换 XML 。像往常一样,这样做有几个原因(它更简单、更快等)。如果你不喜欢建设者的概念,你可以使用Thrift。
无论如何,protobuf 允许创建一个向后兼容的系统(就存储的数据而言)几乎没有头痛。顺便说一句,优势不错。让您的系统向后兼容,您可以轻松实现惰性和完全透明的升级。它可以是后台进程或根据请求进行升级等。好消息是零停机时间、快乐的用户以及更频繁地进行升级的能力。这意味着您可以快速发展,及时响应客户的要求,换句话说,您可以取得更大的成功。
5 级 对不起,这次不是。请注意升级策略。销售一个定义了一些模式的系统并把自己锁在外面是很容易的。没有新功能——没有客户。
简单但非常有用的清单:
感谢您的阅读。
我个人使用liquibase。非常少数的工具。允许非常复杂的工作流程,例如教程,使用 oracle 和复杂的版本控制方案
对表和视图的更改不会保留在它们自己的文件中。您将为所做的每个更改创建一个新的更改脚本。因此,如果您将表 'X' 更改 5 次,那么每次更改都会有 5 个不同的更改脚本。
当您想创建某个版本的架构时,您将获得标记为该版本的源代码。从基线创建数据库。然后按时间顺序在该版本的代码中运行更改脚本。例如
db_scripts/
2012-01-01 baseline.sql:
create table book (
book_name varchar(100),
author_name varchar(100)
)
--- label version_1.0
2012-02-01 add_publisher.sql:
alter table book add column publisher varchar(100)
--- label version_1.1
2012-03-01 add_publish_date.sql:
alter table book add column publish_date datetime
--- label version_1.2
2012-04-01 add_rating.sql:
alter table book add column rating integer
--- label version 1.3
现在假设您要从 1.2 版开始重新创建数据库:
您可以使用 Flyway ( http://flywaydb.org/ ) 而不是 Liquibase,它允许您编写自己的升级/降级 SQL 脚本。这提供了更大的灵活性,也适用于视图和存储过程。
Liquibase 要求您使用他们自己的基于 XML 的语言进行模式更改,这可能会有些限制。
在数据库中保留版本号并在启动时应用更新脚本是该策略的重要部分。
以下是启动的工作原理:
例子:
有一些注意事项。这工作得相当好;人们声称它应该是 100% 可靠的,但事实并非如此。
脚本不完整、字段长度变化或服务器版本不同等问题有时会导致脚本/SQL 在某些数据库上传递,但在其他数据库上失败。
找到要运行的脚本,可以像使用许多 IF 语句的大型单一方法一样简单。或者您可以更优雅地通过发现或元数据加载脚本。有时能够包含程序代码很有用,而不仅仅是 SQL。
public void runDatabaseUpgrades() {
if (version < 790) {
// upgrade Customer and Account tbls
version = 790;
}
if (version < 791) {
// upgrade Email tbl
version = 791;
}
}