Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将@Version与Envers一起使用_Java_Hibernate_Jpa_Spring Boot_Hibernate Envers - Fatal编程技术网

Java 将@Version与Envers一起使用

Java 将@Version与Envers一起使用,java,hibernate,jpa,spring-boot,hibernate-envers,Java,Hibernate,Jpa,Spring Boot,Hibernate Envers,我的应用程序使用SpringBoot、Hibernate和SpringDataJPA来实现这一神奇。我正在尝试将Hibernate的Envers库添加到这个库中,以进行修订跟踪。但是,我在Envers和@Version注释之间遇到了一些冲突 默认情况下,Envers不会审核任何带有@Version注释的字段。这对我来说很有意义,因为@Version只是为了跟踪乐观锁定,所以我实际上不需要保存它的修订历史记录 然而,我遇到的问题是,当我得到一个修订实体时,它不会随版本一起返回。这很有意义-Enve

我的应用程序使用SpringBoot、Hibernate和SpringDataJPA来实现这一神奇。我正在尝试将Hibernate的Envers库添加到这个库中,以进行修订跟踪。但是,我在Envers和@Version注释之间遇到了一些冲突

默认情况下,Envers不会审核任何带有@Version注释的字段。这对我来说很有意义,因为@Version只是为了跟踪乐观锁定,所以我实际上不需要保存它的修订历史记录

然而,我遇到的问题是,当我得到一个修订实体时,它不会随版本一起返回。这很有意义-Envers将修订实体存储在…_AUD表中,而该表没有版本列,因此该实体显然没有版本。问题是,我有时想将该实体用作另一个事务*的一部分,但因为它没有版本,所以该实体被认为是暂时的,并引发异常

因此,我有一些不同的解决方案,但没有一个看起来是理想的,所以我希望能得到一些关于实现这一点的最佳方法的意见:

  • 我可以获取修订实体,然后使用修订实体中的id进行单独的存储库调用以获取实际实体,然后只使用该实体。这将增加很多复杂性(特别是在确定要使用的正确存储库时)和一个似乎不必要的额外数据库调用

  • 我可以保存这个版本。这并不理想,因为它不是我真正关心的信息,但如果它意味着一个有效的系统,我可以处理它。我也尝试过这个方法,但遇到了一些问题(在我的配置中将doNotAuditOptimsticLockingField设置为true似乎没有任何作用),但是如果确定这是最好的解决方案,我将打开一个单独的问题来处理它

  • 我可能会更改无法使用ID而不是实际实体的存储库调用,但如果我必须更改许多其他存储库调用才能实现这一点,我也不会感到惊讶

  • 如果有第四种选择,我洗耳恭听

    *:另一个事务是将实体转换为REST端点返回的资源时发生的数据库调用。我拥有的实体之一是AccountEntity。我获取的修订实体由以下方法使用:

    LinkOwnerEntity findByAccountEntity(AccountEntity accountEntity);
    
    linkOwner实体类如下所示:

    public class LinkOwnerEntity {
    
        ...
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "ACCOUNT_ID", unique=true, foreignKey = @ForeignKey(name = "FK_OWNER_ACCOUNT_ID"))
        private AccountEntity accountEntity;
    
        ...
    
    }
    

    乐观锁定就是确保您看到的数据就是您将要修改的数据。因此,当用户决定在屏幕上恢复旧版本时(我想这就是您希望使用Envers所做的),他应该会看到内容的当前版本和要恢复的内容的旧版本。您需要保留用户视为当前版本的版本字段,并将其发送到应用程序的请求中,并使用它保存修改


    这样,如果数据在用户查看后已被修改,他的修改将被拒绝,而不是覆盖其他人的修改。

    乐观锁定就是要确保您看到的数据是您将修改的数据。因此,当用户决定在屏幕上恢复旧版本时(我想这就是您希望使用Envers所做的),他应该会看到内容的当前版本和要恢复的内容的旧版本。您需要保留用户视为当前版本的版本字段,并将其发送到应用程序的请求中,并使用它保存修改


    这样,如果数据在用户查看后被修改,他的修改将被拒绝,而不是覆盖其他人的修改。

    在我深入讨论我认为您应该做的事情之前,我想澄清几件事

    首先,无论如何,您都不应该将Envers查询API提供给您的实例视为分离的实体实例

    根据对实体的注释方式,从Envers检索的实例很可能是已审核历史行数据和当前行表数据的混合体。实例是真实实体实例管理的属性子集也是可行的,因为您可能只选择跟踪特定属性

    因此,我个人不会考虑将检索到的实例用作与事务中的托管实体关联的东西,至少不盲目。 其次,您的问题不一定清楚的是,首先查询enver,然后将结果作为映射中的关联使用,而不是简单地对实际实体执行查询的真正目的

    因此,最终这让我想到我的建议,这将是你的选择3或它的变体

    听起来您可能想研究使用
    Session#load
    EntityManager#getReference
    。这两种方法旨在基于给定的标识符构建代理实例,然后您可以在关联映射期间盲目使用该代理,而无需直接水合实例的开销(从而避免数据库调用开销)


    这种方法还避免了在这里使用enversqueryapi,因为根据您在问题中提供的内容,我根本看不到它在这个用例中的相关性。如果有具体原因需要涉及Envers查询,请更新您的问题。

    在我深入讨论我认为您应该做的事情之前,我想澄清几件事

    首先,无论如何,您都不应该将Envers查询API提供给您的实例视为分离的实体实例

    根据对实体的注释方式,从Envers检索的实例很可能是已审核历史行数据和当前行表数据的混合体。它是