Все поля @Version в таблице AUD равны нулю при использовании hibernate-envers, но в сущности - таблица заполнена, окей? - PullRequest
0 голосов
/ 18 января 2019

есть приложение spring + jpa + envers (hibernate) envers необходимо сохранить историю сущностей в специальной таблице.

После того, как я несколько раз сохранил свою сущность, я ожидал увидеть заполненное поле версии в таблице USER и заполненное поле версии в USER_AUT. Но фактическим результатом является правильное значение в таблице USER, но добавлены REV_TYPE, столбцы REV (в полях только couter для всех строк) и ноль в столбцах версий.

Я использую 4.0.1. Окончательный режим гибернации

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-envers</artifactId>
    <version>4.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.0.1.Final</version>
</dependency>

Но, когда я смотрю в таблицу, все значения в поле Version равны нулю

Моя сущность

import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.Audited;

import javax.persistence.*;

@Entity
@Audited
@Table(name = "User", uniqueConstraints = {
        @UniqueConstraint(columnNames = { "prKey"})})
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@AllArgsConstructor
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(name = "PR_KEY", unique = true)
    private String prKey;

    @Column(name = "name", length = 100, unique = false)
    private String name;

    @Version
    private int version;

    public User(String name){
        this.name = name;
    }
}

А когда я получаю юридические лица, использующие аудит:

 public List<User> getHistory(String id) {
        AuditReader auditReader = AuditReaderFactory.get(entityManagerFactory.createEntityManager());

        List<Number> auditVersions = auditReader.getRevisions(User.class, id);
        List<User> users = auditVersions.stream().map(item -> auditReader.find(User.class, id, item.intValue())).collect(Collectors.toList());

        return extractRiskMetrics(riskMetricRecords);
    }

Итак, моя настойчивость - конфиг

@Configuration
@EnableTransactionManagement
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = {"persistence"})
@ComponentScan(basePackages = {"persistence", "model"})
public class PersistenceConfig {
    private static final String PACKAGE_WITH_JPA_ENTITIES = "persistence";
    private final Logger log = Logger.getLogger(getClass());

    @Bean
    @Resource(type = DataSource.class, lookup = "jdbc/MyDatasource", name = "jdbc/MyDatasource")
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        dsLookup.setResourceRef(true);
        DataSource dataSource = dsLookup.getDataSource("java:comp/env/jdbc/MyDatasource");
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
        entityManager.setDataSource(dataSource());
        entityManager.setPackagesToScan(PACKAGE_WITH_JPA_ENTITIES);
        entityManager.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        entityManager.setJpaProperties(getHibernateProperties());
        log.info("Entity Manager configured.");
        return entityManager;
    }

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }

    //Set properties hibernate
    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.OracleDialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "none");
        properties.put("org.hibernate.envers.do_not_audit_optimistic_locking_field", false);

        properties.put("verifyServerCertificate", false);
        properties.put("useSSL", false);
        properties.put("requireSSL", false);
        properties.put("useLegacyDatetimeCode", false);
        properties.put("useUnicode", "yes");
        properties.put("characterEncoding", "UTF-8");
        properties.put("serverTimezone", "UTC");
        properties.put("useJDBCCompliantTimezoneShift", true);
        return properties;
    }
}

Обновление:

org.hibernate.envers.do_not_audit_optimistic_locking_field установлено в false, но поля версии по-прежнему нулевые.

Может быть, это связано с конфликтом Spring Data Jpa и Hibernate - envers?

На самом деле выполненный запрос (измененный и ф.с.)

[1/22/19 14:04:51:996 MSK] 00000096 SystemOut     O Hibernate: update UserRecord set User=?, version=? where PR_KEY=? and version=?
[1/22/19 14:04:51:998 MSK] 00000096 SystemOut     O Hibernate: select hibernate_sequence.nextval from dual
[1/22/19 14:04:52:000 MSK] 00000096 SystemOut     O Hibernate: insert into REVINFO (REVTSTMP, REV) values (?, ?)
[1/22/19 14:04:52:002 MSK] 00000096 SystemOut     O Hibernate: insert into UserRecord_AUD (REVTYPE, busId, User, UserType, someInfo, PR_KEY, REV) values (?, ?, ?, ?, ?, ?, ?)

Итак, в таблице AUD нет версии где =?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Как вы упомянули - REVINFO - это централизованная таблица для всех проверяемых объектов.

Основная идея, представленная ниже, состоит в том, чтобы переназначить номера ревизий в целочисленную последовательность, поэтому RevNumber (2,5,31,125) будет переназначен на customVersion (1,2,3,4)

Допустим, у вас есть EntityA, и вы хотите получить все ревизии для него (и сопоставить все данные ревизий с пользовательским классом RevisionEntityDto).

Используя AuditReader из Envers, вы можете сделать что-то вроде:

AuditReader auditReader = AuditReaderFactory.get(entityManager);
//getRevisions() returns revisions sorted in ascending order (older revisions come first)
List<Number> entityARevisions = auditReader.getRevisions(EntityA.class, primaryKeyOfEntityA);

//entityARevisions is already sorted;
for (int customVersion = 0; customVersion < entityARevisions.size(); customVersion++) {
   createRevisionEntityDto(primaryKeyOfEntityA, auditReader, revision, customVersion);
}

private RevisionEntityDto createRevisionEntityDto(Long primaryKeyOfEntityA, AuditReader, Number revision) {
  EntityA revisionOfEntityA = auditReader.find(EntityA.class, primaryKey, revision);
  Date revDate = auditReader.getRevisionDate(revision);
  // at this point you have a single revision of EntityA
  return toRevisionEntityDto(revision, revisionOfEntityA, revDate);
}

private RevisionEntityDto toRevisionEntityDto(Number revision, EntityA revisionOfEntityA, Date revisionDate, int customVersion) {
  //here you do the mapping logic;
  RevisionEntityDto revEntityDto = new RevisionEntityDto();
  revEntityDto.setFieldA(revisionOfEntityA.getFieldA);
  revEntityDto.setDate(revisionDate); // you can use the date to sort if you want at a later stage;
  revEntityDto.setCustomVersion(customVersion);
  return revEntityDto;
}
0 голосов
/ 21 января 2019

Посмотрите на настройку конфигурации org.hibernate.envers.do_not_audit_optimistic_locking_field.

Этот параметр конфигурации определяет, будет ли Hibernate Envers включать аннотированное поле @Version в схему аудита или нет. По умолчанию для этого параметра установлено значение true, что означает, что поле оптимистической блокировки не будет проверяться. Установив значение false, вы будете проверять значение столбца.

Я хочу предупредить вас о настройке этого поля на false.

Если ваше приложение выполняет явную функцию приращения оптимистической блокировки, это приведет к добавлению дополнительных строк в таблицу истории аудита, даже если ни один из других столбцов базы данных не будет изменен как часть вашего бизнес-процесса. Это связано с тем, что после включения отслеживания полей @Version Hibernate Envers просто обрабатывает их как любой другой базовый атрибут объекта. Следовательно, принудительное приращение оптимистической блокировки вызовет изменение аудита.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...