2

我需要存储分层数据的更改历史记录。数据是一对多的关系:一个设置实体有很多属性。这是我的表:

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


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

我使用 Hibernate 作为 ORM,相应的 Java 实体看起来有点像这样

public class Setting {

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

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

现在,每当设置名称更改或将属性添加到设置中时,我都需要存储更改的完整历史记录。我还需要轻松查询给定时间点的历史设置。我考虑了多种不同的选择,即:

  1. 在“设置”表中添加一个“更改日期”列(告诉我们何时修改了给定的设置版本)和一个“通用 ID”列(告诉我们哪些实体及时形成了单个设置的历史记录 - 即如果名称更改新设置版本有一个新名称和一个新 ID,因此我们需要说明这只是同一设置的新版本)。这很简单,应该可以工作,但会使查询大多数当前数据变得困难(即 SELECT * FROM Setting WHERE ChangeDate = (SELECT MAX(ChangeDate ...))
  2. 有一个只有一个 Id、一个 BLOB(用于保存整个序列化的 Java Setting 对象)和一个 ChangeDate 的表。这样我就可以只使用一个表,但是当我想在 Setting 对象中添加/删除某些东西时我遇到了大麻烦,因为我需要更新已经保存的对象。
  3. 为上面的每个表都有一个单独的历史表(具有相同的列和 ChangeDate)——这使得查询当前数据变得容易(只需使用常规表),但是维护几个具有几乎相同模式的表是一些小麻烦。

有什么建议或更好的想法吗?请记住,我使用的是 Hibernate,因此并非所有 SQL 查询怪癖都是可能的。我的数据库是 PostgreSQL。

4

2 回答 2

1

最终我们决定使用Hibernate Envers,因为它为我们完成了所有工作

所以我们将使用它为我们生成的任何映射表:)

于 2013-09-30T11:40:23.767 回答
0

我没有使用历史表的经验,但这可能会有所帮助:

首先,我建议让您友好的邻居 DBA 检查您的数据库架构。虽然我不是 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). 
于 2013-09-26T18:35:21.420 回答