Сохранение в JPA-репозитории: продолжить сохранение после нарушения ограничения вставки - PullRequest
1 голос
/ 12 февраля 2020

Я использую репозиторий JPA для сохранения простых объектов данных в базе данных. Чтобы избежать дубликатов, я создал уникальное ограничение для нескольких полей. Если теперь необходимо сохранить дубликат в соответствии с уникальными полями / ограничениями, я хочу перехватить исключение, зарегистрировать объект, и приложение должно продолжить работу и сохранить следующий объект. Но здесь я всегда получаю это исключение: «org.hibernate.AssertionFailure: нулевой идентификатор в записи de.test.PeopleDBO (не грипп sh Сессия после возникновения исключения)».

В общем, я понять, что делает hibernate, но как я могу отменить сеанс или начать новый сеанс, чтобы продолжить сохранение следующих объектов данных. Пожалуйста, посмотрите на код ниже:

PeopleDBO. java

@Entity
@Data
@Table(
        name = "PEOPLE", 
        uniqueConstraints = {@UniqueConstraint(columnNames = {"firstname", "lastname"}})
public class PeopleDBO {

    public PeopleDBO(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

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

    private String firstname;

    private String lastname;

}

Тест:

public void should_save_people_and_ignore_constraint_violation(){
    final List<PeopleDBO> peopleList = Arrays.asList(
        new PeopleDBO("Georg","Smith"),
        new PeopleDBO("Georg","Smith"),
        new PeopleDBO("Paul","Smith")
    );

    peopleList.forEach(p -> {
        try {
            peopleRepository.save(p);
        } catch (DataIntegrityViolationException e) {
            log.error("Could not save due to constraint violation: {}",p);
        }
    }

    Assertions.assertThat(peopleRepository.count()).isEqualTo(2);
}

Проблема в том, что с сохранением Вторые люди, уникальное ограничение нарушается. Журнал ошибок происходит, и при следующем вызове peopleRepository.save () генерируется упомянутое выше исключение:

"org.hibernate.AssertionFailure: нулевой идентификатор в записи de.test.PeopleDBO (не грипп) sh Сессия после возникновения исключения) "

Как мне избежать этого поведения? Как я могу очистить сессию или начать новую сессию?

Заранее большое спасибо d.

--------- Редактировать / новая идея ------ Я просто попробовал кое-что и увидел, что могу реализовать PeopleRepositoryImpl, например:

@Service
public class PeopleRepositoryImpl {

    final private PeopleRepository peopleRepository;

    public PeopleRepositoryImpl(PeopleRepository peopleRepository) {
        this.peopleRepository = peopleRepository;
    }

    @Transactional
    public PeopleDBO save(PeopleDBO people){
        return peopleRepository.save(people);
    }
}

В моих тестах это работает довольно хорошо. ... что ты думаешь?

1 Ответ

2 голосов
/ 12 февраля 2020

Одна отдельная транзакция

Причина в том, что все вставки происходят в одной транзакции . Поскольку эта транзакция atomi c, она либо завершается успешно, либо завершается неудачно, между ними нет ничего.

Самое чистое решение - проверить, существует ли People, прежде чем пытаться вставить it:

public interface PeopleRespository {

    boolean existsByLastnameAndFirstname(String lastname, String firstname);
}

, а затем:

if (!peopleRepository.existsByLastnameAndFirstname(p.getLastname, p.getFirstname)) {
    peopleRepository.save(p);
}

Одна транзакция на людей

Альтернативой действительно является запуск новой транзакции для каждого человека. Но я не уверен, что это будет более эффективно, поскольку создание транзакции требует дополнительных затрат.

...