如何在数据库应用程序中实现版本控制?

时间:2016-10-02 12:02:59

标签: database version-control

我正在开发一个基于Web的Java项目,它将最终用户数据存储在MySql数据库中。我想实现一些允许用户具有与我的源代码版本控制(例如Subversion)类似的功能的东西。换句话说,我想实现允许用户提交和回滚工作并返回现有分支的代码。是否有现有的框架?似乎将数据库数据放入版本控制并向最终用户公开版本控制功能(即允许用户提交,回滚等的编写代码)可能是一种合理的方法,但它似乎也可能是一些问题用这种方法。例如,您如何允许一个用户查看数据的回滚版本(即,如果一个用户想要查看数据的回滚版本,您不能只替换数据库指向的数据)?如果可以选择使用任何持久性体系结构完全重建系统,那么可以用来存储使这类功能易于实现的数据?

3 个答案:

答案 0 :(得分:3)

有两种非常常见的解决方案可满足您的需求:

答案 1 :(得分:1)

分支和合并用户数据

您的问题是关于在应用程序中对用户数据进行版本化的解决方案,以便为您的用户提供分支和合并等功能。你考虑过暴露一个真正的版本控制,比如svn。

我可以预见的副作用是:

  • 您必须按目录和文件名索引内容。也许使用目录的抽象作为实体和文件名作为主键。
  • 操作系统(linux,mac和windows等)不能处理包含数百万个文件的目录。您必须对实体进行分区。通常散列ID(例如md5)并将散列的开头创建一个子目录。从散列中获取的位数取决于实体的预期大小。
  • 操作系统(linux,mac和windows等)不适用于大量文件。我做了一个测试。我花了几天时间备份并最终删除了包含数亿个文件的文件树。
  • 除了主键之外,您将无法拥有其他索引,但是您可以解决创建数据集市的问题,我将在下面介绍。
  • 您不会有数据库限制,但可以通过git / svn / cvs触发器实现类似的功能。
  • 您不会有强大的交易,但可以通过git / svn / cvs触发器实现类似的功能。
  • 您将拥有每个用户的工作副本,这将占用空间,具体取决于存储库的大小。这样每个用户将处于一个单一的时间点。
  • GIT足够快,可以从一个分支切换到另一个分支,所以回过头来回来只需几秒钟(当然,除非用户数据很大)。
  • 我看到了一个Linus采访,他警告说在巨大的git存储库中表现不佳。也许最好为每个用户提供一个存储库或其他方法,以避免您的应用程序有一个单一的庞大存储库。
  • 更改的解决方案。我敢打赌,如果您创建了大量版本,任何版本控制都会投诉。我不是什么意思。你必须测试它。

查询数据库

版本控制工作副本将仅限于使用" ="的主键查询。操作员和顺序扫描。这还不足以对我能想到的任何使用模式做出好的报告和统计。这就是您需要从应用程序数据构建数据集市的原因,并且您有两种方法:

  • 批处理:读取整个存储库历史记录并构建多维数据集和其他视图以便于查询。
  • GIT / SVN / CVS触发器:可以调用您在文件添加,修改,排除,分支创建和合并方面所做的程序。这可以用于在发生更改时更新数据库。

批处理更容易实现,但报告和统计信息需要时间与活动同步。您可能希望在1.0版本中采用这种方式,并及时转向触发器以使事物更具动态性。

模拟约束和交易

GIT,SVN和CVS支持在提交新版本时执行程序的触发器。然后可以检查关系和一致性以接受或不接受更改。

替代解决方案

由于您没有指定所需的应用程序类型,我将讨论博客,内容门户和在线商店。对于那些类型的应用程序,我认为没有太多理由重新发明轮子并构建自定义数据库。大多数必要的版本控制都可以在数据库模型中预测。一个好的面向事件的数据库设计就足够了。

例如,博客文章中的修订版可以建模为标记帖子的结束日期/时间并为修订后的帖子创建新行,增加版本号并设置以前的版本ID。相同的策略可以与在线商店的销售和目录一起使用。如果使用良好的日志为应用程序建模,则不需要版本控制。

一些开发人员还会执行行级触发器,记录数据库中已更改的所有内容。对于需要从错误设计的日志重建过去的审计员来说,这有点困难。我个人不喜欢这种方式,因为很难索引这类查询。我更喜欢将我的整个应用程序围绕一个设计良好且有意义的日志。

例如:

History Table
10/10/2010 [new process] process_id=1; name=john
11/10/2010 [change name] process_id=1; old_name=john; new_name=john doe
12/10/2010 [change name] process_id=1; old_name=john doe; new_name=john doe junior

Process Table after 12/10/2010.
proc_id=1 name=john doe junior

通过这种方式,我可以重建过去的几乎所有内容,并且仍然以易于使用的格式提供我的操作数据。

但是,这并不接近您想要的使用模式(分支和合并)

结论

版本控制作为数据库的适用性一方面在我看来非常强大,另一方面非常有限和危险。它对于审计和纠错目的非常鼓舞人心。但我主要担心的是规模和可靠性。

答案 2 :(得分:-1)

你提到了Subversion,它是一个集中版本控制系统。但是,由于原因,让我们专注于Git。 Git是一个分散版本控制系统。如果存在远程副本(GitLab和GitHub等服务提供远程外壳和管理Git项目),Git存储库的本地副本与存储库的远程副本相同。使用Git,您可以在计算机的任意目录中进行版本控制。您可以在此任意目录中执行您习惯使用SVN的任何操作,等等。

我得到的是,您可以通过编程方式在服务器中创建每个用户目录/存储库,并在这些目录/存储库中应用版本控制,为每个用户保留一个单独的存储库(将确定架构的细节)但是,稍后,取决于用户的“工作”的结构。您的应用程序将负责代表用户添加和删除文件(例如,传记,我的示例项目等),编辑文件,提交更改,呈现文件历史记录等,基本上发布Git命令。因此,您的应用程序将与Git存储库连接,利用Git提供的高级版本控制。您的数据库只会确保用户链接到包含其“工作”的目录/存储库。

为了提供一个关键的类比,GitLab项目是一个基于Web的开源Git存储库管理器,具有维基和问题跟踪功能。 GitLab是用Ruby编写的,并使用PostgreSQL(最好)。它是典型的(如代码 - 数据库 - 数据目录和文件中)多用户基于Web的应用程序。其目的是管理Git存储库。这些Git存储库存储在服务器的指定目录中。部分代码负责访问登录用户有权访问的Git存储库(作为所有者或协作者)。一个有趣的用例是用户在线编辑文件,这将导致某些存储库中某个分支的提交。另一个有趣的用例是用户检查文件的历史记录。最后一个有趣的用例是用户恢复特定提交。所有这些操作都是通过网络浏览器在线执行的。

为了提供一个有趣的实际用例,O'Reilly的Atlas是一个使用GitLab作为后端进行出版相关协作的在线平台。

对于Java,有JGit,一个实现Git版本控制系统的轻量级纯Java库。 Eclipse使用JGit进行与管理Git存储库相关的所有操作。也许你可以调查一下。这是一个非常活跃的项目,由许多人支持。

以上所有内容都有意义,如果您引用的“工作”不仅仅是数据库表中的某些字段,用户将填写这些字段,以后可能会更改其值。例如,它对结构化文本,HTML等有意义。

如果这个“工作”不是那么大规模,那么做一些类似于上面描述的事情就是矫枉过正。在这种情况下,您可以在数据库设计中使用一些版本控制概念,例如计算差异和应用补丁(反过来,用于查看过去的版本/回滚)。你的表应该允许树状结构,以存储差异,所以你可以允许分支。您可以随时使用文件的活动版本,以及活动索引(Git调用HEAD),并通过顺序应用所有补丁(如果向前移动)导航到文件历史记录中的另一个索引/散列/标记版本,或者如果向后移动,则以相反的时间顺序应用补丁。如果这个“工作”真的是小规模的,你甚至可以放弃差异概念,并将整个版本的“工作”存储在树状结构中。

纯粹的乐趣。