Автор оригинала: Vlad Mihalcea.
Контекст сохранения действует как кэш транзакций для записи за входящими переходами состояний сущностей , и все изменения синхронизируются с базой данных во время очистки.
Хотя и Hibernate Session
, и JPA EntityManager
определяют метод flush()
для ручного запуска этого процесса, гораздо удобнее позволить Hibernate управлять сбросом контекста сохранения. К сожалению, существует большая разница между тем, как JPA и Hibernate определяют механизм автоматической промывки.
При использовании режима AUTO
flush по умолчанию контекст сохранения должен быть сброшен следующим образом:
- до совершения транзакции,
- перед выполнением запроса JPQL или HQL
- перед выполнением собственного SQL-запроса
Как ранее объяснялось , Hibernate запускает АВТО
сброс только для первых двух событий, и собственные SQL-запросы должны либо переопределять ВСЕГДА
режим сброса, используя Запрос#setFlushMode(FlushMode FlushMode)
метод, либо добавлять синхронизацию табличного пространства (например, SqlQuery#addSynchronizedEntityClass(класс entityClass)
, SqlQuery#addSynchronizedEntityName(имя объекта строки)
, SqlQuery#addSynchronizedQuerySpace(пространство строковых запросов)
).
Это требуется только для собственного API гибернации при явном использовании сеанса
.
Начиная с Hibernate 5.2, если вы загружаете Hibernate с помощью JPA (например, persistence.xml
), затем даже тип Hibernate Flush.AUTO
будет вести себя точно так же, как его аналог JPA. Только в том случае, если вы загрузите режим гибернации с использованием собственного механизма, сеанс гибернации | будет использовать устаревший тип
Flush.АВТО поведение.
JPA более строгий, и режим AUTO
flush должен запускать сброс перед любым запросом. Подробнее в разделе 3.10.8
в спецификации API сохранения Java говорится, что режим AUTO
flush должен гарантировать, что все ожидающие изменения будут видны любому выполняемому запросу.
Это можно продемонстрировать, выполнив следующий метод:
assertTrue(((Number) entityManager .createNativeQuery("select count(*) from Post") .getSingleResult()).intValue() == 0); Post post = new Post("Hibernate"); post.setId(1L); entityManager.persist(post); assertTrue(((Number) entityManager .createNativeQuery("select count(*) from Post") .getSingleResult()).intValue() == 1);
При выполнении этого теста Hibernate генерирует следующие инструкции SQL:
SELECT COUNT(*) FROM Post INSERT INTO post (title, version, id) VALUES ('Hibernate', 0, 1) SELECT COUNT(*) FROM Post
Таким образом, был запущен сброс, и инструкция INSERT
была выполнена до запуска инструкции SELECT
.
Этого не происходит при использовании Сеанса
:
assertTrue(((Number) entityManager .createQuery("select count(*) from Post") .getSingleResult()).intValue() == 0); Post post = new Post("Hibernate"); post.setId(1L); entityManager.persist(post); Session session = entityManager.unwrap(Session.class); assertTrue(((Number) session .createSQLQuery("select count(*) from Post") .uniqueResult()).intValue() == 0);
На этот раз Hibernate генерирует следующие инструкции:
SELECT COUNT(*) FROM Post SELECT COUNT(*) as col_0_0_ FROM post blogentity0_ INSERT INTO post (title, version, id) VALUES ('Hibernate', 0, 1)
Промывка также является очень важной концепцией для любой ФОРМЫ, и Hibernate ничем не отличается. Как правило, лучше убедиться, что собственные SQL-запросы не возвращают противоречивые результаты при использовании API Hibernate Session
.