Правильное использование flush () в JPA / Hibernate - PullRequest
105 голосов
/ 25 ноября 2010

Я собирал информацию о методе flush (), но мне не совсем понятно, когда его использовать и как его правильно использовать. Из того, что я прочитал, я понимаю, что содержимое контекста постоянства будет синхронизировано с базой данных, т.е. е. выдача невыполненных заявлений или обновление данных объекта.

Теперь я получил следующий сценарий с двумя сущностями A и B (в отношении один-к-одному, но не применяется или не моделируется JPA). A имеет составной PK, который устанавливается вручную, а также имеет автоматически сгенерированное поле IDENTITY recordId. Этот recordId должен быть записан в сущность B как внешний ключ к A. Я сохраняю A и B в одной транзакции. Проблема в том, что автоматически сгенерированное значение A.recordId недоступно в транзакции, если я не сделаю явный вызов em.flush() после вызова em.persist() на A. (Если у меня есть автоматически сгенерированный PK IDENTITY, то значение непосредственно обновляется в сущности, но здесь это не так.)

Может ли em.flush() причинить какой-либо вред при использовании его в транзакции?

Ответы [ 3 ]

133 голосов
/ 25 ноября 2010

Вероятно, точные детали em.flush() зависят от реализации. В общем, в любом случае провайдеры JPA, такие как Hibernate, могут кэшировать инструкции SQL, которые они должны отправлять в базу данных, часто до тех пор, пока вы фактически не совершите транзакцию. Например, вы вызываете em.persist(), Hibernate помнит, что он должен сделать INSERT базы данных, но фактически не выполняет инструкцию, пока вы не совершите транзакцию. Афаик, это в основном делается из соображений производительности.

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

Что делает em.flush(), так это очищает внутренний кэш инструкций SQL и немедленно выполняет его в базе данных.

Итог: никакого вреда не будет, только у вас может быть (незначительное) снижение производительности, так как вы игнорируете решения поставщика JPA в отношении наилучшего времени для отправки инструкций SQL в базу данных.

2 голосов
/ 08 января 2018

На самом деле em.flush() делает больше, чем просто отправляет кэшированные команды SQL.Он пытается синхронизировать контекст постоянства с базовой базой данных.Это может привести к значительному расходу времени на ваши процессы, если ваш кэш содержит коллекции для синхронизации.

1 голос
/ 12 июня 2019

Может ли em.flush () причинить какой-либо вред при использовании его в транзакции?

Да, он может удерживать блокировки в базе данных дольше, чем необходимо.

Как правило, при использовании JPA вы делегируете управление транзакциями контейнеру (a.k.a CMT - с помощью аннотации @Transactional для бизнес-методов), что означает, что транзакция автоматически запускается при входе в метод и фиксируется / откатывается в конце. Если вы позволите EntityManager обрабатывать синхронизацию базы данных, выполнение операторов sql будет запущено только перед фиксацией, что приведет к кратковременным блокировкам в базе данных. В противном случае операции записи, очищенные вручную, могут сохранить блокировки между ручным сбросом и автоматической фиксацией, которые могут быть длинными в соответствии с оставшимся временем выполнения метода.

Отмечает, что некоторые операции автоматически вызывают сброс: выполнение собственного запроса в том же сеансе (состояние EM должно быть сброшено, чтобы быть доступным для SQL-запроса), вставка объектов с использованием собственного сгенерированного идентификатора (созданного базой данных, поэтому вставка оператор должен быть запущен, поэтому EM может получить сгенерированный идентификатор и правильно управлять отношениями)

...