Проблема данных Spring - org.hibernate.HibernateException: идентификатор экземпляра {Entity} был изменен с 1 на 2 - PullRequest
0 голосов
/ 21 января 2019

У меня есть это исключение при смене родителя для сущности (отношение @OneToMany).

Обновление родительского объекта - org.hibernate.HibernateException: идентификатор экземпляр {Entity} был изменен с 1 на 2

Это исключение возникает и может быть воспроизведено только для службы, работающей в Kubernetes, через некоторое время. Я имею в виду, что он не воспроизводится с самого начала срока службы контейнера, и некоторое количество обновлений успешно завершено.

Метод, который выполняет обновление сущностей, выглядит следующим образом:

@Transactional
    @Override
    public Optional<EntityT> update(EntityT entity) {

        entity.setIsConfirmed(true);

        return getRepository().findById(entity.getId())
                .map(entityToUpdate -> updateEntity(entity, entityToUpdate));
    }


private EntityT updateEntity(EntityT entity, EntityT entityToUpdate) {
        modelMapper.map(entity, entityToUpdate);

        getParentRepository().ifPresent(parentRepository ->
                entity.getParent().ifPresent(parentEntity ->
                        parentRepository.findById(parentEntity.getId()).ifPresent(entityToUpdate::setParent))
        );

        entityToUpdate.setVersionTs(getCurrentTime());
        return getRepository().save(entityToUpdate);
    }

Spring boot version - 2.1.2 Hibernate 5.3.7 также попробуйте 5.4.1 - тот же результат.

Также установите свойства jpa пружины на

spring:
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    generate-ddl: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        jdbc:
          batch_size: 100
        flushMode: "ALWAYS"
        order_inserts: true
        order_updates: true

Также пробовал разные образы для контейнера open-jdk8 / oracle-jdk8

Может кто-нибудь посоветовать какое-нибудь решение?

Спасибо за совет.

Ответы [ 2 ]

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

Основная проблема была в маппере. Вместо замены родителя, измените только id для извлеченного родителя. Затем мы заменяем родительский, но извлеченный родительский остается в кэше (с новым идентификатором), и Hibernate через некоторое время пытается сбросить эти изменения в БД.

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

Во-первых, updateEntity использует избыточный анти-шаблон сохранения :

private EntityT updateEntity(EntityT entity, EntityT entityToUpdate) {
    modelMapper.map(entity, entityToUpdate);

    getParentRepository().ifPresent(parentRepository ->
            entity.getParent().ifPresent(parentEntity ->
                    parentRepository.findById(parentEntity.getId()).ifPresent(entityToUpdate::setParent))
    );

    entityToUpdate.setVersionTs(getCurrentTime());
    return getRepository().save(entityToUpdate);
}

Во-вторых, эта часть здесь не нужна:

getParentRepository().ifPresent(parentRepository ->
            entity.getParent().ifPresent(parentEntity ->
                    parentRepository.findById(parentEntity.getId()).ifPresent(entityToUpdate::setParent))
    );

Тот факт, что вы используете entity и entityToUpdate, является запахом кода, который, вероятно, связан с использованием лямбд, которые также не нужны.

Итак, вы, вероятно, можете сократить весь свой код до этого:

@Transactional
@Override
public Optional<EntityT> update(EntityT entity) {

    entity.setIsConfirmed(true);
    entity.setVersionTs(getCurrentTime());
    return getRepository().save(entity);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...