Правильне використання flush () в JPA / Hibernate


110

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

Тепер я отримав наступний сценарій з двома сутностями Aта B(у взаємовідносинах один на один, але не застосовується та моделюється JPA). Aмає складений ПК, який встановлюється вручну, а також має автоматично створене поле ІДЕНТИЧНОСТІ recordId. Це recordIdмає бути записане суб'єктом господарювання Bяк зовнішній ключ A. Я заощаджую Aі Bоднією транзакцією. Проблема полягає в тому, що автоматично сгенерированное значення A.recordIdне доступно в угоді, якщо не зробити явний виклик em.flush()після виклику em.persist()на A. (Якщо у мене є автоматично сформований ПК IDENTITY PK, то значення безпосередньо оновляється в об'єкті, але це не так.)

Чи може em.flush()заподіяти шкоду при використанні її в рамках транзакції?

Відповіді:


148

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

У деяких випадках ви хочете, щоб інструкції SQL були виконані негайно; як правило, коли вам потрібен результат деяких побічних ефектів, наприклад, автогенерованого ключа або тригера бази даних.

Що потрібно em.flush()- це спорожнити внутрішній кеш інструкцій SQL та негайно виконати його до бази даних.

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


1
Що він сказав. Поведінка em.flush () перегукується з java.io.Flushable.flush (), де всі завантажені дані надсилаються в будь-яке місце призначення.
Ерік

4
якщо flush () надсилає дані в базу даних? що станеться, якщо після цього буде викинуто виняток? Чи все відкатає менеджер юридичних осіб? навіть дані, записані в першому флеш?
Хайме Хаблуцель

101
flush () надсилає інструкції SQL до бази даних, наприклад INSERT, UPDATE тощо. Він не надсилатиме COMMIT, тому якщо у вас є виняток після flush (), ви все одно можете мати повний відкат.
Флавіо

17
Ви можете відкатати БД, але він не відкидає жодних змін об’єктів, наприклад, автоматично збільшеної 'версії', автогенерованого ідентифікатора тощо. Крім того, менеджер об'єктів буде закритий після відкату. Будьте обережні, якщо ви спробуєте "об'єднати" об'єкт до іншого сеансу, зокрема, "автоматично" збільшена "версія" може спричинити OptimisticLockException.
Пітер Девіс

11
Крім запуску побічних ефектів, ще одна причина використовувати flush () - це якщо ви хочете мати можливість читати ефекти операції в базі даних за допомогою JPQL / HQL (наприклад, у тесті). JPA не може використовувати кешовані дані під час виконання цих запитів, тому читатимуться лише ті речі, які є насправді в БД.
sleske

2

Насправді, em.flush()роби більше, ніж просто надсилає кешовані команди SQL. Він намагається синхронізувати контекст стійкості з базовою базою даних. Це може спричинити велику витрату часу на ваші процеси, якщо ваш кеш містить колекції для синхронізації.

Застереження щодо його використання.


1

Чи може em.flush () заподіяти шкоду при використанні його в рамках транзакції?

Так, він може зберігати блоки в базі даних довше, ніж це потрібно.

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.