Hibernate Envers 旧值-新值

Hibernate Envers Old-New Values

我有一个 table 如下所示。

╔════╦══════════════╦══════╗
║ Id ║     User     ║ Age  ║
╠════╬══════════════╬══════╣
║  1 ║ Foo Bar      ║  35  ║
║  2 ║ Bar Foo      ║  40  ║
║  3 ║ Bob Dixon    ║  50  ║
║  4 ║ Alice Spolsky║  59  ║
╚════╩══════════════╩══════╝

现在这些是初始值,我想使用 Hibernate Envers 存储审计,包括所有值、旧值和新值。默认配置让我只存储新值,因此我错过了第一个创建的对象的值。例如,如果我说将第一个年龄更新为 55,那么 aud table 将如下所示(不包括详细信息列):

╔════╦══════════════╦══════╗
║ Id ║     User     ║ Age  ║
╠════╬══════════════╬══════╣
║  1 ║ Foo Bar      ║  55  ║
╚════╩══════════════╩══════╝

而且在这之后我不知道初始值是不是35。我需要的就像下面的审计table:

╔════╦══════════════╦══════════╦═════════╗
║ Id ║     User     ║ OldAge   ║ New Age ║
╠════╬══════════════╬══════════╬═════════╣
║  1 ║ Foo Bar      ║  35      ║   55    ║
╚════╩══════════════╩══════════╩═════════╝

如何使用 Hibernate Envers 实现此类审计?

看来您可能是

  1. 手动设置数据库并绕过 Hibernate
  2. 为已有数据的实体映射启用 Hibernate Envers

为了让 Envers 响应更改,通过 Hibernate 完成数据库更改至关重要,以便其事件框架触发所有负责生成审计历史记录的 Envers 侦听器。如果任何步骤绕过这个,将不会生成审计条目。

Envers 也不会为已有数据的实体映射生成审计历史记录。期望你的实体 table 是空的,插入、更新和删除事件将被 Hibernate 捕获,传播到 Envers,审计历史将根据这些发生变化。使用现有数据,没有事件,因此不会自动生成审计历史记录。如果您打算使用现有数据在 table 上启用审计,则实施者需要正确地 播种 审计历史记录。

因此,如果我们退后一步,假设您没有在一个实体上手动播种或启用 Envers,其数据已经存在于 ORM 库 table,那么更新后您的审计 table 应该是这样的:

+---+--------------------+-----+-----+---------+
|Id | User               | Age | REV | REVTYPE |
+---+--------------------+-----+-----+---------+
| 1 | Foo Bar            |  35 |   1 |       0 |
| 2 | Bar Foo            |  40 |   1 |       0 |
| 3 | Bob Dixon          |  50 |   1 |       0 |
| 4 | Alice Spolsky      |  59 |   1 |       0 |
| 1 | Foo Bar            |  55 |   2 |       1 |
+---+--------------------+-----+-----+---------+

您会注意到 REVTYPE 列。此列表示与行突变关联的操作。这些值是枚举类型的一部分,其中:

  • 0 = 插入
  • 1 = 更新
  • 2 = 删除

Envers 查询 API 允许您获取给定实体主键的修订号列表,您可以从那里获取每个修订并使用任何差异库执行对象实例之间的差异或编写您的拥有。

Envers 还支持名为 withModifiedFlags 的注释属性。默认情况下这是禁用的,因为它向实体模型添加了大量额外的支持列,但启用后您的模型实际上如下所示:

+---+--------------------+----------+-----+---------+-----+---------+
|Id | User               | User_MOD | Age | Age_MOD | REV | REVTYPE |
+---+--------------------+----------+-----+---------+-----+---------+
| 1 | Foo Bar            |        1 | 35  |       1 |   1 |       0 |
| 2 | Bar Foo            |        1 | 40  |       1 |   1 |       0 |
| 3 | Bob Dixon          |        1 | 50  |       1 |   1 |       0 |
| 4 | Alice Spolsky      |        1 | 59  |       1 |   1 |       0 |
| 1 | Foo Bar            |        0 | 55  |       1 |   2 |       1 |
+---+--------------------+----------+-----+---------+-----+---------+

这些 _MOD 列很有用,因为它允许您构建复杂的查询以检查某些感兴趣的列是否在修订版中发生了更改。虽然它不允许您从当前审计行中获取以前的值,但可以通过查看该实体主键的审计 table 历史来推断该信息。

您可能会问,如果 Envers 可以添加这些 _MOD 列,为什么不能添加这些 "prior-value" 列。理论上我们可以做到这一点,但我认为重要的是退后一步并衡量这是否真的有价值。

我认为增强查询 API 的方式更有价值两次修订之间的生命周期。然后,此表示将允许您从中获取先前值和当前值。

简而言之,这样就不需要更改架构,因为 API 会完全为您在实际操作中完成此操作。