Я вижу странное поведение с 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
, исключение выдается во время сброса, происходящего непосредственно перед фиксацией транзакции, что на самом деле не то, что я хочу.