Что происходит при совершении транзакции из диспетчера объектов, который не содержит какого-либо грязного объекта? Может ли быть, что команда COMMIT не отправляется в БД?JPA фиксирует изменения, сделанные путем развернутого соединения
У меня были некоторые тестовые случаи, которые случались сейчас, а затем без разумной причины. После некоторого расследования у меня теперь есть теория, которую я хотел бы подтвердить здесь.
У меня есть небольшая инфраструктура для подготовки данных к БД для каждого теста. Светильники используют такой способ для хранения объектов в БД с использованием JPA (Hibernate):
public <R> R doInTransaction(final Function<EntityManager, R> whatToDo) {
final EntityManager em = emf.createEntityManager();
final R result;
try {
try {
em.getTransaction().begin();
result = whatToDo.apply(em);
em.getTransaction().commit();
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
} finally {
em.close();
}
return result;
}
Таким образом, прибор вызывает этот метод, проходящий функцию whatToDo, где сохранялись объекты и метод оборачивает транзакцию вокруг переданной функции , В моих неудачных тестовых случаях используется прибор, который использует устаревший код, который использует хранимые процедуры и сохраняет объекты непосредственно через JDBC, т.е. е. вместо того, чтобы использовать em.persist()
, я использую следующий в переданной функции для вызова хранимых процедур:
em.unwrap(Session.class).doWork(connection -> {
// stored procedures are called here directly over JDBC
});
Итак, моя теория состоит в том, что JPA этого обстоятельства не сразу совершение, как нет JPA грязных объектов, управляемых EntityManager. Следовательно, фактические фиксации происходят только позже, т.е. е. после утверждения моего теста и теста не удается. Может быть?
Что такое транзакционное поведение Hibernate при «разворачивании» соединения из EntityManager?
Я добавил em.flush()
до em.getTransaction().commit()
, и, похоже, это помогает, но я все еще не уверен на 100%, что это решает проблему. Может кто-нибудь подтвердить?
Вы должны быть осторожны при смешивании и сопоставлении обработчиков персистентности. Hibernate поддерживает тайник, который грязный, а что нет. Если вы обновляете вещи за пределами hibernate, есть возможность спящего режима выйти из синхронизации с db и сбросить обновление, поскольку он считает, что его кешированная версия объекта по-прежнему действительна. Я несколько лет назад сталкивался с такими проблемами, и если я правильно помню, мы отключили кеш в режиме спящего режима, чтобы предотвратить его поведение. – Stephan
Я предпочитаю не входить в таинственный мир кеширования в Hibernate ... :) Если 'em.flush()' будет выполнять эту работу здесь, этого было бы более чем достаточно для меня. – Alex
Если вы в тестовой среде, вы всегда можете попробовать em.flush() и посмотреть. Что касается настроек кеша, если вы не ожидаете смешного количества одновременных пользователей, вы должны быть в состоянии отключить кеш в спящем режиме и позволить кешу в базе данных обрабатывать большую часть работы. Другое дело, кэширование по умолчанию db может помешать кэшированию по умолчанию для спящего режима. Я настоятельно рекомендую отключить кэш гибернации, если вы продолжаете сталкиваться с проблемами. – Stephan