【问题标题】:Auditing Embeddable Entity using Hibernate Envers使用 Hibernate Envers 审计可嵌入实体
【发布时间】:2019-11-16 00:28:13
【问题描述】:

我正在尝试将使用 Hibernate Envers 的审计支持添加到存储实体关系的表中。

我正在使用 Spring Boot 2.1.5 和 Hibernate 5.3.10。

以下是我的课程:

审计实体

import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.envers.Audited;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;

@Getter
@Setter
@Audited
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditEntity {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(
            name = "uuid",
            strategy = "org.hibernate.id.UUIDGenerator",
            parameters = {
                    @Parameter(
                            name = "uuid_gen_strategy_class",
                            value = "org.hibernate.id.uuid.CustomVersionOneStrategy"
                    )
            }
    )
    private String id;

    @Column(name = "created_date", updatable = false, nullable = false)
    @CreatedDate
    private long createdDate;

    @Column(name = "modified_date")
    @LastModifiedDate
    private long modifiedDate;

    @Column(name = "created_by")
    @CreatedBy
    private String createdBy;

    @Column(name = "modified_by")
    @LastModifiedBy
    private String modifiedBy;

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof AuditEntity)) {
            return false;
        }

        AuditEntity r = (AuditEntity) o;

        return this.getId().equals(r.getId());
    }
}

角色

import lombok.Getter;
import lombok.Setter;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Getter
@Setter
@Audited
@Entity
@Table(name = "role")
public class Role extends AuditEntity {
    @Column(name = "name")
    private String name;

    @NotAudited
    private String dontAudit;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.role")
    private Set<UserRole> userRoles = new HashSet<>(0);
}

用户

import lombok.Getter;
import lombok.Setter;
import org.hibernate.envers.Audited;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.HashSet;
import java.util.Set;

@Getter
@Setter
@Audited
@Entity
@Table(name = "user")
public class User extends AuditEntity {
    private String sso;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.user")
    private Set<UserRole> userRoles = new HashSet<>(0);
}

用户角色

import lombok.Getter;
import lombok.Setter;
import org.hibernate.envers.Audited;

import javax.persistence.*;

@Getter
@Setter
@Audited
@Entity
@Table(name = "user_roles")
@AssociationOverrides({
        @AssociationOverride(name = "pk.user", joinColumns = @JoinColumn(name = "USER_ID")),
        @AssociationOverride(name = "pk.role", joinColumns = @JoinColumn(name = "ROLE_ID"))
})
public class UserRole extends AuditEntity {
    @EmbeddedId
    private UserRoleId pk = new UserRoleId();

    public User getUser() {
        return getPk().getUser();
    }

    public void setUser(User user) {
        getPk().setUser(user);
    }

    public Role getRole() {
        return getPk().getRole();
    }

    public void setRole(Role role) {
        getPk().setRole(role);
    }
}

用户角色标识

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
import java.io.Serializable;

@Getter
@Setter
@Embeddable
@EqualsAndHashCode
public class UserRoleId implements Serializable {
    @ManyToOne
    private User user;
    @ManyToOne
    private Role role;
}

当我运行应用程序时,它会抛出以下错误。但是当我不从 AuditEntity 扩展 UserRole 时,应用程序启动成功,但 user_role 表上没有审计列。

错误

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.MappingException: Type not supported: org.hibernate.type.ComponentType
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    at com.ercancelik.hibernate.envers.DemoApplication.main(DemoApplication.java:11) [classes/:na]
Caused by: org.hibernate.MappingException: Type not supported: org.hibernate.type.ComponentType
    at org.hibernate.envers.configuration.internal.metadata.IdMetadataGenerator.addIdProperties(IdMetadataGenerator.java:120) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.configuration.internal.metadata.IdMetadataGenerator.addId(IdMetadataGenerator.java:200) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.configuration.internal.metadata.AuditMetadataGenerator.generateFirstPass(AuditMetadataGenerator.java:642) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.configuration.internal.EntitiesConfigurator.configure(EntitiesConfigurator.java:95) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.boot.internal.EnversServiceImpl.doInitialize(EnversServiceImpl.java:154) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.boot.internal.EnversServiceImpl.initialize(EnversServiceImpl.java:118) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl.produceAdditionalMappings(AdditionalJaxbMappingProducerImpl.java:101) ~[hibernate-envers-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:297) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57) ~[spring-orm-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390) ~[spring-orm-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) ~[spring-orm-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    ... 16 common frames omitted

【问题讨论】:

  • @C. Weber,我使用的是较新版本的 Hibernate,您提供的链接中提到的错误已在旧版本中解决。此外,我正在尝试将审计支持添加到存储关系的表中。如果我从 UserRole 类中删除“扩展 AuditEntity”部分,应用程序将成功启动,但 user_roles 表不包含 AuditEntity 列。
  • 我链接这个问题主要是因为提到了复合 id 并且它们会导致 envers 出现问题。据我所知,您的 UserRole 有一个 EmbeddedId 可能是您问题的根源?

标签: java hibernate spring-boot jpa hibernate-envers


【解决方案1】:

问题在于您如何映射UserRole。如果你看你已经定义了UserRole 来包含一个@EmbeddedId,但是你也扩展了你的AbstractEntity 类,它也基于一个uuid 定义了它自己的标识符。您根本无法将这两个问题混为一谈。

说实话,我很惊讶您提供的映射实际上并没有引发 ORM 异常,而不是您一直进入 Envers,因为 ORM 最初必须在最终应该引发的地方解析它们关于如何解析标识符的异常。

作为旁注,除非有特定的业务目的来捕获在主数据表中创建或修改实体的人/时间,否则您实际上可以将其捕获为 Envers 修订实体的一部分,在每个事务中审计数据,这将减少每条记录存储的数据。

查看 Envers 提供的自定义修订实体;您可以使用 spring-bean 连接到那里,并使用结合 Hibernate 5.3+ 的最新 Spring Framework 收集您需要的任何信息。

【讨论】:

    猜你喜欢
    • 2015-12-14
    • 2011-07-10
    • 2013-08-27
    • 2012-12-05
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 2023-03-24
    • 2013-06-28
    相关资源
    最近更新 更多