简体   繁体   English

使用Hibernate进行分层数据版本控制的最佳数据库设计是什么?

[英]What's a good database design for hierarchical data versioning with Hibernate?

I need to store a history of changes for hierarchical data. 我需要存储分层数据的更改历史记录。 The data is a one-to-many relation: a setting entity has many properties. 数据是一对多关系:设置实体具有许多属性。 Here are my tables: 这是我的桌子:

Setting
------------------------------
Id            INTEGER NOT NULL
CompanyId     INTEGER NOT NULL
Name          TEXT NOT NULL


SettingProperty
------------------------------
SettingId            INTEGER NOT NULL
PropertyName         TEXT NOT NULL

I'm using Hibernate as the ORM, the corresponding Java entity would look somewhat like this 我使用Hibernate作为ORM,相应的Java实体看起来像这样

public class Setting {

    private int id;
    private int companyId;
    private String name;

    private Set<String> properties;
    // ....
}

Now, whenever the setting name changes or a property is added to the setting, I need to store the full history of changes. 现在,每当设置名称更改或将属性添加到设置时,我都需要存储更改的完整历史记录。 I also need to easily query the historical setting for a given point in time. 我还需要轻松查询给定时间点的历史设置。 I've taken into account multiple different options, ie: 我考虑了多个不同的选项,即:

  1. adding into the 'Setting' table a 'ChangeDate' column (tells us when the given setting version was modified) and a 'CommonId' column (tells us which entities form the history of a single setting in time - ie in case when the name changes the new setting version has a new name and a new id so we need to way to tell that this is just a new version of the same setting). 在“设置”表中添加一个“ ChangeDate”列(在修改给定设置版本时告诉我们)和一个“ CommonId”列(告诉我们哪些实体在时间上形成了单个设置的历史记录,例如当名称更改,新的设置版本具有一个新的名称和一个新的ID,因此我们需要说明这只是同一设置的新版本)。 This is simple and should work but makes querying for most current data hard (ie SELECT * FROM Setting WHERE ChangeDate = (SELECT MAX(ChangeDate ...)) 这很简单,应该可以工作,但是很难查询大多数当前数据(即SELECT * FROM Setting WHERE ChangeDate =(SELECT MAX(ChangeDate ...))
  2. having a table with just an Id, a BLOB (for keeping the whole serialized Java Setting object) and a ChangeDate. 有一个只有一个ID的表,一个BLOB(用于保留整个序列化的Java Setting对象)和一个ChangeDate。 This way I'm fine with just one table, but I'm in big trouble when I want to add/remove something into the Setting object because I need to update the already saved objects. 这样,我只用一个表就可以了,但是当我想在Setting对象中添加/删除某些东西时,我遇到了很大的麻烦,因为我需要更新已经保存的对象。
  3. having for each of the above tables a separate History table (with same columns and a ChangeDate) - this makes it easy to query for current data (just use the regular tables) but maintaining a few tables with almost identical schema is some minor pain. 对于上述每个表,都有一个单独的“ History”表(具有相同的列和一个ChangeDate)-这使查询当前数据(仅使用常规表)变得容易,但是维护几个具有几乎相同模式的表则有些麻烦。

Any suggestions or better ideas? 有什么建议或更好的主意吗? Please keep in mind that I'm using Hibernate so not all SQL query quirks are possible. 请记住,我正在使用Hibernate,因此并非所有SQL查询怪癖都是可行的。 My DB is PostgreSQL. 我的数据库是PostgreSQL。

Eventually we decided to use Hibernate Envers because it does al the work for us 最终我们决定使用Hibernate Envers,因为它确实为我们完成了工作

So we'll use whatever mapping tables it generates for us :) 因此,我们将使用它为我们生成的任何映射表:)

I don't have experience with history tables, but this might help: 我没有使用历史记录表的经验,但这可能会有所帮助:

First, I would suggest having your friendly neighborhood DBA review your database schema. 首先,我建议让您的友好邻居DBA审查您的数据库架构。 Although I'm not a DBA, here are a few suggestions: 尽管我不是DBA,但这里有一些建议:

Setting
        settingID           long not null, primary key
        companyID           long not null, foreign key to Company table
        name                varchar(255) not null, unique

SettingProperty
        settingPropertyID   long not null, primary key
        settingID           long not null, foreign key to Setting table
        name                varchar(255) not null, unique

Company
        companyID           long not null, primary key
        name                varchar(255) not null, unique
        abbr                varchar(50), unique


Notes: 
       0: primary keys are always named with the table name followed by 'ID'.
       1: Table names begin with a capital letter
       2: column names begin with a lower case letter
       3: primary keys are to have no business meaning        
       4: primary and foreign keys are long and not int 
       to ensure the max value isn't likely to be reached.
       5: I suggest you consider calling your tables something 
       more meaningful than Setting and SettingProperty (assuming
       there is such a meaning).
       6: Consider adding company abbreviation to your Company 
       table (abbr), which can be null, but must be unique.
       7:Don't add columns to the database tables being audited
         with auditing information. They should be ignorant of the fact
         they are being audited.
       8: Use database triggers to update a history table when a record
         is updated, inserted, or deleted. Don't do it in Java.
       9: Search Google for 'store historical data in database triggers' or similar search
          on how to best create a history table.
         Example:
       https://www.google.com/#q=storing+historical+data+in+database+triggers&start=10
       10: There is a column with not null and unique, and another with nullable and unique.
         Some databases don't like nullable and unique (it treats more than one null in the 
         column as violating the unique rule). 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM