Автор оригинала: 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 .