Неожиданное исключение дубликата ключа - PullRequest
0 голосов
/ 12 февраля 2019

Я вижу странное поведение с Spring Boot 2.0.4 + Hibernate.

У меня есть объект, включающий случайно сгенерированный код.Если сгенерированный код уже установлен для другой сущности, DataIntegrityViolationException генерируется как ожидалось.Таким образом, цикл может повторить попытку с новым кодом, который, мы надеемся, не используется.Когда это происходит, цикл продолжается, генерируется новый код, и вызов saveAndFlush() снова вызывает то же исключение, говоря, что исходный код, вызвавший проблему (предыдущая итерация), уже используется (дубликат).Однако сейчас я устанавливаю новый код, а не тот, о котором упоминает исключение.

Единственное, о чем я могу думать, это то, что Hibernate не удаляет операцию из «очереди», поэтому при втором вызовена saveAndFlush() происходит, он все еще пытается выполнить первое сохранение, а затем новое.Очевидно, что первое сохранение завершается неудачно, как и во время первой итерации.Может быть, я ошибаюсь, но тогда что здесь происходит?

@Entity
public class Entity {

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

    @Column(nullable = false, unique = true)
    private int code;

    public void setCode(int code) {
        this.code = code;
    }

    //Other properties

}

@Transactional
public void myFunction() {
    boolean saved = false;
    do {
        int code = /* Randomly generated code */;
        if(entity == null) {
            entity = new Entity(code, /* other properties */);
        } else {
            entity.setCode(code);
        }

        try {
            entity = myRepository.saveAndFlush(entity);
            saved = true;
        } catch (DataIntegrityViolationException e) {
            /* Ignore so that we can try again */
        }
    } while(!saved);
}

РЕДАКТИРОВАТЬ:

Если я заменю saveAndFlush() на save()проблема исчезает.Я где-то видел, что сохранение после предыдущего неудачного сохранения может быть проблематичным, если также вызывается flush().Это как раз мой случай.Однако я не понимаю, почему это проблема.Единственная причина, по которой я называю saveAndFlush() вместо save(), - перехватить исключение дубликата ключа.Используя save(), если Hibernate не выполняет напрямую INSERT или UPDATE, исключение выдается во время сброса, происходящего непосредственно перед фиксацией транзакции, что на самом деле не то, что я хочу.

1 Ответ

0 голосов
/ 12 февраля 2019

Если вы отлаживаете код и видите состояние постоянства, вы можете получить ответ.Вы правы, что hibernate поддерживает своего рода очередь, то есть все запросы, сделанные во время транзакции, будут выполняться при фиксации / сбрасывании.

Пожалуйста, опубликуйте значение контекста постоянства, которое вы получаете при отладке.

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