版本控制数据库持久化对象,你会怎样?

时间:2008-09-24 07:41:41

标签: database database-design versioning

(与版本化数据库架构无关)

与数据库接口的应用程序通常具有由来自许多表的数据组成的域对象。假设应用程序支持CVS意义上的这些域对象的版本控制。

对于某些仲裁域对象,您如何设计数据库模式来处理此要求?有分享的经验吗?

9 个答案:

答案 0 :(得分:22)

仔细考虑修订的要求。一旦您的代码库具有内置于操作系统中的普遍历史记录跟踪,它将变得非常复杂。 Insurance underwriting systems特别糟糕,模式通常超过1000个表。查询也往往非常复杂,这可能会导致性能问题。

如果历史状态实际上仅用于报告,请考虑实施“当前状态”交易系统,其背面悬挂数据仓库结构以跟踪历史记录。 Slowly Changing Dimensions是一种更简单的跟踪历史状态的结构,而不是试图将特殊历史记录跟踪机制直接嵌入到您的操作系统中。

此外,对于“当前状态”系统,Changed Data Capture更简单,对记录进行了更改 - 记录的主键不会更改,因此您不必匹配保持不同的记录同一实体的版本在一起。一个有效的CDC机制将使增量仓库加载过程相当轻量级并且可以非常频繁地运行。如果您不需要对历史状态进行最新的跟踪(几乎,但不完全和矛盾),这可以是一个有效的解决方案,其代码库比直接构建到应用程序中的完整历史记录跟踪机制简单得多。

答案 1 :(得分:12)

我过去使用的一种技术是在数据库中有一个“代”的概念,每次更改都会增加数据库的当前代数 - 如果使用subversion,请考虑修订。 每条记录都有2个与之关联的代数(表中有2个额外的列) - 记录开始有效的代,以及它停止生成的代。如果数据当前有效,则第二个数字将为NULL或其他一些通用标记。

所以要插入数据库:

  1. 增加世代号
  2. 插入数据
  3. 使用有效的from和有效的NULL
  4. 标记该数据的生命周期

    如果您要更新某些数据:

    1. 将所有要修改为有效的数据标记为当前世代号
    2. 增加世代号
    3. 使用当前世代号
    4. 插入新数据

      删除只是将数据标记为在当前一代终止。

      要获取特定版本的数据,请查找您正在使用的代,并查找在这些代版本之间有效的数据。

      示例:

      创建一个人。

      |Name|D.O.B  |Telephone|From|To  |
      |Fred|1 april|555-29384|1   |NULL|
      

      更新电话号码

      |Name|D.O.B  |Telephone|From|To  |
      |Fred|1 april|555-29384|1   |1   |
      |Fred|1 april|555-43534|2   |NULL|
      

      删除fred:

      |Name|D.O.B  |Telephone|From|To  |
      |Fred|1 april|555-29384|1   |1   |
      |Fred|1 april|555-43534|2   |2   |
      

答案 2 :(得分:2)

严格版本控制的替代方法是将数据拆分为2个表:当前和历史。

当前表包含所有实时数据,并具有您构建的所有性能的优势。 任何更改首先将当前数据与日期标记一起写入关联的“历史”表中,该日期标记表示更改时间。

答案 3 :(得分:2)

如果您使用Hibernate JBoss Envers可能是一个选项。您只需要使用@Audited注释类以保留其历史记录。

答案 4 :(得分:1)

您需要在主表中包含主记录,其中包含所有版本中共有的信息。

然后每个子表使用主记录id +版本号作为主键的一部分。

可以在没有主表的情况下完成,但根据我的经验,它会使SQL语句变得更加混乱。

答案 5 :(得分:0)

一种简单的万无一失的方法是向表中添加一个版本列并存储Object的版本,并根据该版本号选择适当的应用程序逻辑。 这样,您也可以获得向后兼容性,而且成本很低。哪个总是好的

答案 6 :(得分:0)

ZoDB + ZEO实现基于修订版的数据库,并完全回滚到任何时间点支持。去检查一下。

不好的部分:这是Zope并列。

答案 7 :(得分:0)

一旦将对象保存在数据库中,我们可以正确地修改该对象,如果我们想知道对象被修改了多少次,那么我们需要应用这个版本控制概念。

当我们使用版本控制时,然后hibernate将版本号插入为零,当数据库中第一次保存对象时。稍后,当对该特定对象进行修改时,hibernate会自动将该版本增加一个。 为了使用此版本控制概念,我们需要在应用程序中进行以下两项更改

Add one property of type int in our pojo class.

In hibernate mapping file, add an element called version soon after id element

答案 8 :(得分:0)

我不确定是否存在相同的问题,但是我需要对当前数据集进行大量的“提议”更改(使用链式提议,即提议中的提议)。

在源代码管理中考虑分支,但在数据库表中考虑。

我们还希望有一个历史记录,但这是最不重要的因素-主要问题是管理变更建议,由于企业考虑变更批准并为实施实际变更做好准备,这些变更建议可能会持续6个月或更长时间

这个想法是,用户可以加载更改并开始创建,编辑,删除数据的当前状态,而无需实际应用这些更改。恢复他们可能进行的任何更改,或取消整个更改。

我能够实现这一目标的唯一方法是在我的版本表中拥有一组通用字段:

根ID :必需-在创建记录的第一个版本时将一次设置为主键。它始终代表主键,并被复制到记录的每个版本中。在命名关系列时(例如,PARENT_ROOT_ID而不是PARENT_ID),您应该考虑Root ID。由于根ID也是初始版本的主键,因此可以根据实际的主键创建外键-实际所需的行将由下面定义的版本过滤器确定。

更改ID :必需-通过更改创建,更新和删除每条记录

从ID复制:可为空-null表示新创建的记录,非null表示更新时从该行克隆的记录ID

从日期/时间开始生效:可为空-null表示建议的记录,非null表示记录何时成为最新记录。不幸的是,不能在根ID /有效自上放置唯一索引,因为任何根ID可能有多个空值。 (除非您希望将自己限制为每条记录仅提议更改一次)

对日期/时间有效:可为空-null表示当前/提议,null表示它何时成为历史。在技​​术上不是必需的,但有助于加快查询查找当前数据的速度。手动编辑可能会损坏该字段,但如果发生这种情况,则可以从“有效起始日期/时间”重新构建。

删除标志:布尔值-如果建议在记录成为当前记录时删除记录,则将其设置为true。提交删除后,将其“有效截止日期/时间”设置为与“有效起始日期/时间”相同的值,从而将其从当前数据集中过滤掉。

根据更改获取当前数据状态的查询将是

SELECT * FROM table WHERE (CHANGE_ID IN :ChangeId OR (EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now) AND ROOT_ID NOT IN (SELECT ROOT_ID FROM table WHERE CHANGE_ID IN :ChangeId)))

(对变化倍数的过滤是在此查询之外进行的。)

查询某个时间点的当前数据状态的查询将是

SELECT * FROM table WHERE EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now)

在(ROOT_ID,EFFECTIVE_FROM),(EFFECTIVE_FROM,EFFECTIVE_TO)和(CHANGE_ID)上创建的公用索引。

如果有人知道更好的解决方案,我很想听听。