2014-12-31 2 views
6

У моего объекта есть как открытый ключ (id), так и бизнес-ключ (пространство имен). Мне нужно обновить запись, заменив старый. Итак, я ищу его с помощью бизнес-ключа, удаляю его и сохраняю новый объект. Это работает, если каждая операция выполняется в собственной транзакции. Но как только я поместил все их в одну транзакцию, к моменту выполнения save() функция delete() еще не была выполнена, поэтому я получаю нарушение ограничения.Spring JpaRepository: delete() с последующим сохранением() в той же транзакции

transactionTemplate.execute(status -> { 
    MyEntity oldEntity = repository.findByNamespace(namespace); 
    if (oldEntity != null) { 
     repository.delete(oldEntity); 
    } 
    repository.save(newEntity); 
    return null; 
}); 

Я на самом деле удалось обойти его, добавив

repository.flush(); 

Но я действительно не понимаю, почему мне нужен этот флеш().

+1

Я думаю, это потому, что провайдер JPA чувствует себя свободно, чтобы реорганизовать и/или оптимизировать запись базы данных ожидающих изменений из постоянного контекста, в частности, поставщик JPA не чувствует себя обязанным выполнять запись в базе данных в порядке и форме связанных с индивидуальными изменениями постоянного контекста. Во всяком случае, описанная ситуация известна как одна, и флеш() известен как обходной путь. – Michal

ответ

4

Поскольку repository.flush() сбрасывает изменения в базу данных, вызывая EntityManager.flush(). Поэтому, когда вы очищаете изменения после delete(), sql выполняется, и следующее сохранение не будет иметь проблем.

Если вы не вызываете флеш, поставщик провайдера настойчивости должен определить, когда следует сбрасывать изменения, когда время фиксации транзакции является крайним сроком. Также поставщики не сбрасывают изменения в каком-либо конкретном порядке, поэтому может случиться так, что иногда ваша операция преуспевает, а иногда и нет. Как правило, поставщики не ждать до фиксации времени флеша, но вы можете влиять, что, установив режим промывки:

for entitymanager 
EntityManager.setFlushMode(FlushModeType type); 

or for query 
Query.setFlushMode(FlushModeType type); 

Там есть эквивалент установка весной данных JPA также, я уверен, но я не совсем знаете, какой он есть.

Обратите внимание, однако, что немедленное удаление изменений снижает производительность, поэтому при использовании следует соблюдать осторожность. В вашем конкретном случае лучше обновить объект, а затем удалить его, а затем сохранить новый с тем же бизнес-ключом.

Смежные вопросы