
在基于jpa和hibernate envers构建的应用程序中,我们经常需要对实体进行审计,以跟踪数据的历史变更。然而,在处理具有复杂关联关系的实体时,可能会遇到不必要的审计事件,尤其是在保存一个实体时,其关联的另一个实体(即使其自身数据未发生变化)也被误触发审计更新,导致审计表中产生大量冗余记录。这不仅浪费存储空间,也增加了审计数据分析的复杂性。
考虑以下两个JPA实体:TariffOption 和 DictTariff。TariffOption通过@ManyToOne注解关联到DictTariff,表示多个资费选项可以对应一个资费字典。
@Entity
@Audited // 启用审计
@AuditTable(schema = "audit", value = "tariff_option")
@Table(name = "tariff_option")
public class TariffOption extends BaseEntity {
// ... 其他字段
@ManyToOne
@JoinColumn(name = "dict_tariff_id", updatable = false) // 外键列不可更新
private DictTariff tariff;
}@Entity
@Audited // 启用审计
@AuditTable(schema = "audit", value = "dict_tariff")
@Table(name = "dict_tariff")
public class DictTariff extends BaseEntity {
// ... 其他字段
@OneToMany(mappedBy = "tariff", fetch = FetchType.LAZY)
private List<TariffOption> tariffOptions;
}当我们在代码中保存TariffOption实例时,例如通过repository.save(dictTariffOption),即使TariffOption关联的DictTariff实体(即dictTariffOption.getTariff())的自身属性没有任何改变,Hibernate Envers仍然可能会为DictTariff生成一条新的审计记录。这通常是因为Hibernate在处理关联关系时,即使仅仅是集合中的元素发生变化,也可能导致拥有@OneToMany关联的父实体被“脏”检测,进而触发Envers的审计机制。
尝试使用@JoinColumn(updatable = false)仅能阻止外键列的更新,并不能阻止关联实体本身被Envers检测到“脏”而产生审计记录。同样,EntityManager.detach(dictTariff)或重新从数据库加载DictTariff也未能解决此问题,因为Envers的脏检查机制可能在更深层次上工作,或者与会话管理生命周期相关。
要解决这种不必要的审计记录,最直接且有效的方法是利用Hibernate Envers提供的@NotAudited注解。这个注解可以应用于实体类中的特定字段或集合,告诉Envers在审计父实体时,忽略这些被注解的字段或集合的变更。
在这种情况下,问题在于当TariffOption被保存时,DictTariff中的tariffOptions集合被Envers视为可能发生了变化,从而触发了DictTariff的审计。因此,我们应该在DictTariff实体中的tariffOptions集合上添加@NotAudited注解。
@Entity
@Audited
@AuditTable(schema = "audit", value = "dict_tariff")
@Table(name = "dict_tariff")
public class DictTariff extends BaseEntity {
// ... 其他字段
@OneToMany(mappedBy = "tariff", fetch = FetchType.LAZY)
@NotAudited // 关键:阻止对该集合的审计
private List<TariffOption> tariffOptions;
}通过在DictTariff的tariffOptions字段上添加@NotAudited,我们明确指示Envers在审计DictTariff实体时,不要考虑tariffOptions集合的任何变化。这意味着,即使TariffOption被保存或更新,只要DictTariff自身的其他被审计字段没有发生变化,就不会为DictTariff生成新的审计记录。
当TariffOption实体被保存时,由于它与DictTariff存在@ManyToOne关联,Hibernate会管理这种关系。在默认情况下,Envers会监控所有被@Audited标记的实体及其所有字段(除非显式排除)。当一个TariffOption被保存,如果DictTariff中存在@OneToMany关联回TariffOption的集合,Envers可能会检测到DictTariff的这个集合发生了“变化”(例如,集合中的元素数量或内容发生了变化),从而认为DictTariff实体本身需要被审计。
@NotAudited注解的作用是告诉Envers,即使这个字段或集合在持久化操作中看起来发生了变化,也不应将其视为触发父实体审计的依据。它有效地将该字段或集合从父实体的审计范围中排除。因此,当TariffOption被保存时,DictTariff的tariffOptions集合的变化将不再导致DictTariff被审计,从而避免了冗余的审计记录。
通过在@OneToMany关联的集合字段上应用@NotAudited注解,我们能够有效地解决JPA和Hibernate Envers中因关联实体更新导致不必要审计记录的问题。这种方法提供了一种精确控制审计范围的机制,确保只有真正需要审计的实体和字段才会被记录,从而优化了审计系统的效率和数据质量。在设计和实现审计功能时,深入理解Envers的工作原理和灵活运用其提供的注解是至关重要的。
以上就是优化JPA Envers审计:避免不必要的关联实体更新导致过多记录的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号