持久化对象的历史,差异和恢复

时间:2014-09-09 08:42:20

标签: java spring hibernate jpa spring-data

在Spring MVC / Spring Data项目中,我需要实现一种机制来跟踪历史记录,呈现差异并将更改还原为实体对象。

假设我有一个与其他人建立关系的实体:

@Entity
public Class ModelA{
    @OneToOne(cascade = CascadeType.ALL)
    private ModelB modelB;

    @OneToOne(cascade = CascadeType.ALL)
    private ModelC modelC;
}

我希望获得更改列表,比较和还原它们的能力。我知道使用Ruby有提供这种功能的库,但我不知道Java中是否存在这样的东西。

Spring有historiography API并且Hibernate Envers已经被整合到Core功能中,尽管我仍然找不到一个简单的例子或一些如何实现它的指导。

如果它是相关的,使用的数据库是PostgreSQL和Oracle 11g,但我想保持数据库独立。

3 个答案:

答案 0 :(得分:2)

请使用Enver和Auditions

答案 1 :(得分:1)

this article中,Christian Bauer(Hibernate提交者和Hibernate in Action和Java Persistence with Hibernate的作者)给出了一个非常有趣的方法。

您创建一个HISTORY表:

create table ITEM (
    ITEM_ID    NUMBER(19) NOT NULL,
    DESC       VARCHAR(255) NOT NULL,
    PRICE      NUMBER(19,2) NOT NULL,
    PRIMARY KEY(ITEM_ID)
)

create table ITEM_HISTORY (
    ITEM_ID    NUMBER(19) NOT NULL,
    DESC       VARCHAR(255) NOT NULL,
    PRICE      NUMBER(19,2) NOT NULL,
    VERSION    NUMBER(10) NOT NULL,
    PRIMARY KEY(ITEM_ID, VERSION)
)

然后将实体映射到视图:

create or replace view ITEM_VERSIONED (ITEM_ID, VERSION, DESC, PRICE) as
    select I.ITEM_ID as ITEM_ID,
        (select max(IH.VERSION)
            from ITEM_HISTORY HI
            where HI.ITEM_ID = I.ITEM_ID) as VERSION,
        I.DESC as DESC,
        I.PRICE as PRICE
    from   ITEM I

并且由PostgreSQL和Oracle支持的INSTEAD OF TRIGGERS解决了DML语句:

create or replace trigger ITEM_INSERT
    instead of insert on ITEM_VERSIONED begin

    insert into ITEM(ITEM_ID, DESC, PRICE)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE);

    insert into ITEM_HISTORY(ITEM_ID, DESC, PRICE, VERSION)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE, :n.VERSION);
end;

create or replace trigger ITEM_UPDATE
    instead of update on ITEM_VERSIONED begin

    update ITEM set
            DESC = :n.DESC,
            PRICE = :n.PRICE,
           where
            ITEM_ID = :n.ITEM_ID;

    insert into ITEM_HISTORY(ITEM_ID, DESC, PRICE, VERSION)
           values (:n.ITEM_ID, :n.DESC, :n.PRICE, :n.VERSION);
end;

即使对于可能不使用Hibernate的其他应用程序,它也可以工作,但它们在同一个DB上运行。

答案 2 :(得分:0)

如果我理解得很清楚,你要问的是某种Memento pattern来管理一些受历史追踪影响的实体。

在这种情况下,我的建议是将Spring Data配置为支持第二个数据库(即跟踪数据库),您将在其中插入您感兴趣的实体的历史记录。 然后,您可以创建一个新的注释(可能使用AspectJ)并将其应用于您的DAO(例如,如果您正在使用它们,则应用于您的存储库)。这样,每次在跟踪类上(或者更确切地说,在管理要跟踪的类的dao / repository上)进行CRUD操作时,都会在跟踪数据库中进行“插入”,以便存储只有发生。

我可以给你this reference,这与你的需求不完全相符,但可以帮助你找到解决问题的解决方案。