【问题标题】:Hibernate Envers doesn't write anything inside the Audit Tables with SpringMVC configHibernate Envers 不会在带有 SpringMVC 配置的审计表中写入任何内容
【发布时间】:2017-07-27 10:07:56
【问题描述】:

当我保存、更新或删除数据库中的条目时,我正在尝试使用 Enverse 审核表。

Envers 配置如下:

pom.xml

        <!-- Spring -->
        <org.springframework-version>4.1.6.RELEASE</org.springframework-version>

        <!-- Hibernate  -->
        <hibernate.version>4.3.5.Final</hibernate.version>
[...]

    <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-envers</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

我的 jpa-tx-config.xml

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="packagesToScan" value="my.domain"/>

    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop> 
            <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
            <prop key="hibernate.connection.charSet">UTF-8</prop>

            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">20</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.format_sql">true</prop>

            <prop key="org.hibernate.envers.audit_table_suffix">_H</prop>
            <prop key="org.hibernate.envers.revision_field_name">AUDIT_REVISION</prop>
            <prop key="org.hibernate.envers.revision_type_field_name">ACTION_TYPE</prop>
            <prop key="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidityAuditStrategy</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_end_rev_field_name">AUDIT_REVISION_END</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_store_revend_timestamp">True</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name">AUDIT_REVISION_END_TS</prop>               
            <prop key="jadira.usertype.databaseZone">jvm</prop>
        </props>
    </property>
</bean>

我的每个域类都有 @Audited 注释,但在 DB 中,此字段永远是 null

我不明白出了什么问题,有什么建议吗?

编辑

回应评论:每个实体类都扩展了一个抽象域,该域实现了可审计的方式。按照代码:

   @SuppressWarnings("serial")
@MappedSuperclass
@Audited
public abstract class AbstractDomain implements Auditable<String, Long>, Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Version
    private int version;

    @JsonIgnore
    @Column(updatable=false)
    private String createdBy;

    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @DateTimeFormat(iso=ISO.DATE_TIME)
    @JsonIgnore
    @Column(updatable=false)
    private DateTime createdDate;

    @JsonIgnore
    private String lastModifiedBy;

    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @DateTimeFormat(iso=ISO.DATE_TIME)
    @JsonIgnore
    private DateTime lastModifiedDate;

唯一修改的字段是版本,其他字段被忽略。

【问题讨论】:

  • > 但在 DB 中,此字段永远为空。你指的是哪些领域?是否已创建审计表?
  • 您是否在日志中看到任何错误,表明审计操作未发生的原因?也许启用hibernate.show_sql 并将org.hibernate.SQL 设置为trace,以便您可以在日志中查看正在执行的SQL 语句。您是否看到与审计表相关的任何内容?根据您提供的信息,如果没有更多细节,真的很难提供更多帮助。
  • @Naros 我觉得没什么奇怪的。

标签: java spring hibernate spring-mvc hibernate-envers


【解决方案1】:

据我所知,您实际上根本不需要envers。 Envers 更多的是关于存储 revisions 的数据(当然可以用于审计目的),但如果你只想拥有这些 createdBy,createdDate,lastModifiedBy,@ 987654326@字段还有更简单的方法。

由于您已经在使用spring-data-jpa,我建议您使用@EnableJpaAuditing 注释启用JPA auditing

然后你可以从你的AbstractDomain类中删除@Audited并添加@EntityListeners(AuditingEntityListener.class),这将强制休眠每次实体被持久化时保存审计信息。

最后但并非最不重要的事情是定义AuditorAware bean。它会告诉每个时刻究竟是谁在操纵给定的实体,因此审计侦听器将知道应该将哪些数据设置到 createdBylastModifiedBy 字段。 很简单,举个例子:

@Bean
AuditorAware auditor() {
    // return () -> "system";  // Fixed principal
    // and for spring-security
    return () -> {
        Authentication authentication = SecurityContextHolder.getContext()
                .getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        return authentication.getPrincipal().toString();
    }
}

就是这样。

这是一个完整的例子:

@SpringBootApplication
@EnableJpaAuditing
public class So45347635Application {
    public static void main(String[] args) { SpringApplication.run(So45347635Application.class, args); }

    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public static abstract class AbstractDomain extends AbstractPersistable<Long> implements Auditable<String, Long> {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @Version
        private int version;

        @Column(updatable = false)
        private String createdBy;

        @Temporal(TemporalType.TIMESTAMP)
        @Column(updatable = false)
        private Date createdDate;

        private String lastModifiedBy;

        @Temporal(TemporalType.TIMESTAMP)
        @Column(insertable = false)
        private Date lastModifiedDate;

        @Override
        public String getCreatedBy() {
            return this.createdBy;
        }

        @Override
        public void setCreatedBy(String createdBy) {
            this.createdBy = createdBy;
        }

        @Override
        public DateTime getCreatedDate() {
            return null == this.createdDate ? null : new DateTime(this.createdDate);
        }

        @Override
        public void setCreatedDate(DateTime createdDate) {
            this.createdDate = createdDate.toDate();
        }

        @Override
        public String getLastModifiedBy() {
            return this.lastModifiedBy;
        }

        @Override
        public void setLastModifiedBy(String lastModifiedBy) {
            this.lastModifiedBy = lastModifiedBy;
        }

        @Override
        public DateTime getLastModifiedDate() {
            return null == this.lastModifiedDate ? null : new DateTime(this.lastModifiedDate);
        }

        @Override
        public void setLastModifiedDate(DateTime lastModifiedDate) {
            this.lastModifiedDate = lastModifiedDate.toDate();
        }
    }

    @Entity
    @Table(name = "users")
    public static class User extends AbstractDomain {
        private String username = "anonymous";

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        @Override
        public String toString() {
            return String.format("User{id=%d, createdBy='%s', createdDate=%s, lastModifiedBy='%s', lastModifiedDate=%s, username='%s'}",
                    getId(), getCreatedBy(), getCreatedDate(), getLastModifiedBy(), getLastModifiedDate(), username);
        }
    }

    @Bean
    AuditorAware auditor() { return () -> "system"; }

    @Bean
    CommandLineRunner start(UserRepository userRepository, TransactionTemplate tx) {
        return args -> tx.execute(ctx -> {
            final User user = userRepository.save(new User());
            user.setUsername("admin");
            System.out.println(">>>> " + userRepository.save(user));
            return null;
        });
    }
}

interface UserRepository extends CrudRepository<So45347635Application.User, Long> {
}

输出:

create table users (id bigint generated by default as identity, created_by varchar(255), created_date timestamp, last_modified_by varchar(255), last_modified_date timestamp, version integer not null, username varchar(255), primary key (id));
insert into users (id, created_by, created_date, last_modified_by, version, username) values (null, 'system', '28-Jul-17', 'system', 0, 'anonymous');
update users set last_modified_by='system', last_modified_date='28-Jul-17', version=1, username='admin' where id=1 and version=0;

【讨论】:

    猜你喜欢
    • 2017-02-26
    • 2015-08-20
    • 2023-03-24
    • 2016-11-15
    • 1970-01-01
    • 2018-09-19
    • 1970-01-01
    • 2015-12-14
    • 2016-03-19
    相关资源
    最近更新 更多