【问题标题】:How to save additional attributes when using envers使用envers时如何保存附加属性
【发布时间】:2016-12-08 07:58:23
【问题描述】:

我正在使用 Hibernate Envers 作为我的修订历史记录。 这是我的餐桌设置:

CREATE TABLE EPIC (
epicid SERIAL NOT NULL,
accountid BIGINT NOT NULL, 
description TEXT NOT NULL UNIQUE,
epicowner TEXT NOT NULL,
PRIMARY KEY(epicid)
);

CREATE TABLE EPIC_AUD(
epicid BIGINT NOT NULL ,
REV BIGINT NOT NULL,
accountid BIGINT,
description TEXT,
epicowner TEXT,
REVTYPE BIGINT,
PRIMARY KEY(epicid,REV)
);

目前,当我进行更改时,它只保存复合主键值和修订类型。由于我还想记录删除某些实体的用户,所以我也想保存该值。这是我用于删除实体的代码。

@Override
public boolean deleteItem(Epic epicFromFrontend) {
    transactionBegin();
    Epic epicToRemove = getEntityManager().find(Epic.class,  epicFromFrontend.getEpicid());
    epicToRemove.setAccountid(epicFromFrontend.getAccountid());
    getEntityManager().remove(epicToRemove);
    return transactionEnd();
}

其实我有两个问题:

  1. 如何也保存 accountid
  2. 或者保存所有数据可能更聪明更好。所以删除后我的 EPIC_AUD 表中没有空字段。

【问题讨论】:

  • 如果我理解正确的话,docs.jboss.org/hibernate/core/4.0/devguide/en-US/html/… 这样的东西可能会帮助你实现你想要的。
  • 感谢您的回复,但我已经找到了。但是我不是这个的忠实粉丝,因为这意味着我必须创建很多代码来做一件简单的事情。我想知道是否没有任何注释,例如“@Auditthisattribute”或@Auditthisfield
  • 您真正要寻找的是在 RevisionEntity 级别跟踪相关内容,而不是在域实体级别跟踪值。这使您可以轻松地跟踪删除用户,而无需任何侵入性代码来操作您的域模型。

标签: java hibernate-envers


【解决方案1】:

在您的域实体的插入、更新或删除过程中,捕获各种特定于审计的附加信息是一种常见的做法。

按照 Marcin H 的建议,一种简单但侵入性的方法是将状态存储在与实体相同的结构中。虽然这种方法可能有效,但这种方法存在几个问题。

  1. 混合关注
    这里的问题是历史相关信息现在与特定领域的数据一起存储。就像安全性一样,审计是一个跨领域的问题,因此在涉及数据结构时应该以同样的方式对待。此外,由于对架构中的多个审核行进行了操作,您通常会在多个表中表示相同的用户、时间戳等,这会导致不必要的架构和表膨胀。

  2. 用于删除数据的不必要字段/操作
    当您将此 calibur 的字段存储在实体本身上时,它会引入一组有趣的要求作为实体删除过程的一部分。如果您希望 Envers 跟踪该删除用户,那么您要么必须在删除之前对该用户执行实体更新,要么引入一个额外的列来跟踪行是否被软删除,正如 Marcin H 所建议的那样。

    这种方法意味着一个表将永远无限增长,即使删除已被删除。它可能对长期查询性能和其他各种问题产生负面影响。理想情况下,如果数据不再相关,除非出于历史目的,并且没有必须维护的 FK 关系继续存在,那么从非审计表中删除该行要好得多。

我建议使用我发布的here 策略而不是上述策略,该策略描述了如何利用 Envers 的自定义 RevisionEntity 数据结构,允许您跟踪与相关的多列数据当前的事务操作。

这种方法有以下额外的好处:

  1. 您的 DAO 方法中没有散布 Envers(审核)特定代码。您的 DAO 方法继续只关注特定领域的操作,这是应该的。
  2. 在单个事务中操纵多个实体的情况下,您现在只捕获每个事务一次的各种审计属性(也就是每个修订一次)。这意味着如果用户添加、删除和更新不同的行,它们都会被标记一次。
  3. 您现在可以轻松跟踪执行行删除的人员,因为审计属性保存在 RevisionEntity 上,该属性将为删除生成。处理这种情况不需要特殊的操作或字段。此外,您可以启用在删除时存储实体快照,然后可以访问 (1) 谁删除了该行,以及 (2) 该行在删除之前的样子。

【讨论】:

  • 感谢您的回复,我想我会试试看的!
【解决方案2】:

您可以将属性 record_active boolean 添加到您的表 epic 中,当然也可以添加到表 epic_aud 中。 当 record_activefalse 时,表示记录已被“删除”。 并且永远不要物理删除任何记录 - 实际上这是一种很好的做法:)

【讨论】:

  • 我也想到了这一点,但我在表 epic_aud 中的属性仍然具有空值。
  • 为什么?当某个用户想要删除记录时,您的应用程序将 record_status 设置为 false 并将 account_id 设置为该用户的 id。 Envers 使用 record_status 和 account_id 作为当前值创建记录的副本。什么都没有丢失,您只需使用 record_status 过滤记录以忽略“已删除”项目。
  • 也许我理解你是愚蠢的,但表史诗中的所有非PK值都没有保存在表epic_aud中。例如如果我删除一行,它只会填充属性:epicid、rev 和 revtype。如果我要添加一个名为 record_status 的属性并将其设置为 false。错误值未显示在 epic_aud 的记录中
  • 但重点是您不要删除任何记录(至少在该表中)。您不使用 EntityManager.remove(...) 方法。您只需将 record_active 设置为 false,将其持久化并将此值视为记录已被真正删除(但事实并非如此)。
  • 在某些情况下,软删除字段很有用,尤其是在实体之间必须维护外键关系的情况下;但是,在这种情况下使用一个非常具有侵入性。正如我在回答中所描述的那样,更好的解决方案是利用 Envers 的功能来更好地解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-20
  • 2011-07-06
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多