Рубрики
Без рубрики

Как JPA и Hibernate определяют режим автоматической очистки

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