我的应用程序使用SpringBoot,Hibernate和Spring Data JPA来实现魔力。我试图在其上添加Hibernate的Envers库,进行修订跟踪。但是,我在Envers和@Version注释之间遇到了一些冲突。
默认情况下,Envers不会审核使用@Version注释的任何字段。这对我来说很有意义,因为@Version只是为了跟踪乐观锁定,所以我真的不需要保留它的修订历史。
然而,我遇到的问题是,当我获得修订实体时,它并没有回复该版本。这是有意义的 - Envers将修订实体存储在..._ AUD表中,并且该表没有Version列,所以很明显该实体没有版本。问题是我有时想将该实体用作另一个事务*的一部分,但由于它没有版本,因此该实体被视为瞬态并抛出异常。
所以我有一些不同的解决方案,但它们似乎都不理想,所以我希望得到一些关于我能做到这一点的最佳方式的输入:
我可以获取修订实体,然后使用修订实体中的id进行单独的存储库调用以获取实际实体,然后只使用该实体。这会增加很多复杂性(特别是在确定要使用的正确存储库时)以及额外的数据库调用,这似乎是不必要的。
我可以保存版本。这不是理想的,因为它不是我关心的真正信息,但如果它意味着一个有效的系统,我可以处理它。我也尝试了这个并且遇到了问题(在我的配置中将doNotAuditOptimsticLockingField设置为true似乎什么都不做),但如果确定这是最好的解决方案,我将打开一个单独的问题来处理它。 / p>
我可能会更改无法使用ID而非实际实体的存储库调用,但如果我不得不更改其他一些存储库调用,我不会感到惊讶使这项工作。
如果有第4个选项,我全都是耳朵!
*:另一个事务是将实体转换为REST端点返回的资源时发生的数据库调用。我拥有的其中一个实体是AccountEntity。我得到的修订实体由此方法使用:
LinkOwnerEntity findByAccountEntity(AccountEntity accountEntity);
linkOwner Entity类看起来像这样:
public class LinkOwnerEntity {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ACCOUNT_ID", unique=true, foreignKey = @ForeignKey(name = "FK_OWNER_ACCOUNT_ID"))
private AccountEntity accountEntity;
...
}
答案 0 :(得分:0)
乐观锁定就是要确保您看到的数据是您要修改的数据。因此,当用户决定在他的屏幕上恢复旧版本(我想你想要用Envers做什么)时,他应该看到内容的当前版本和他想要恢复的内容的旧版本。您需要将用户看到的版本的版本字段保留为当前版本,并将其发送到您的请求中并将其用于保存修改。
这样一来,如果数据在用户查看后被修改过,那么他的修改将被拒绝,而不是覆盖其他人的修改。
答案 1 :(得分:0)
在深入了解我认为应该做的事情之前,我想澄清一些事情。
首先,在任何情况下,您都不应该将Envers Query API提供的实例视为分离的实体实例。
根据您对实体进行注释的方式,您从Envers检索的实例很可能是经过审计的历史行数据和当前行表数据的混合。实例是您的真实实体实例管理的属性的子集也是可行的,因为您可能只选择跟踪特定属性。
因此,我个人不会考虑将检索到的实例用作我在交易中与托管实体关联的内容,至少不要盲目。
其次,从你的问题中必须清楚的是,首先查询Envers然后将结果用作映射中的关联而不是简单地执行查询中的真实实体的真正目的。第一名。
所以最终这让我得到了我的建议,这将是你的选择3或它的变体。
听起来您可能希望使用Session#load
或EntityManager#getReference
进行调查。这两种方法旨在基于给定的标识符构建代理实例,然后您可以在关联映射期间盲目地使用该代理,而无需直接对实例进行保护(从而避免数据库调用开销)。
这种方法也避免了在这里使用Envers Query API的任何需要,因为根据您在问题中提供的内容,我根本没有看到它在这个用例中的相关性。如果有特定原因涉及Envers查询,请更新您的问题。