#hibernate #jpa-2.0
#спящий режим #jpa-2.0
Вопрос:
Я установил FlushModeType для ФИКСАЦИИ, но сразу после вызова em.persist() ВСТАВКА выполняется в базу данных. Я ожидаю, что Hibernate будет записывать изменения в базу данных только в конце транзакции, но, похоже, это работает по-другому.
Небольшой код для иллюстрации проблемы:
@Entity
@Table(name="tbl1")
@Inheritance(strategy=InheritanceType.JOINED)
public class TopLevelEntity {}
@Entity
@Table(name="tbl2")
public class MyEntity extends TopLevelEntity {
AnotherEntity anotherEntity;
//getters and setters
}
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class AnotherEntity { }
public void someTransaction() {
em.setFlushMode(FlushModeType.COMMIT);
MyEntity e = new MyEntity();
em.persist(e);
e.setProp1(someVal1);
e.setProp2(someVal2);
}
Здесь я ожидаю, что фактическая ВСТАВКА будет выполнена в конце метода, сразу после вызова setProp2() .
Но Hibernate выполняет вставку сразу после вызова em.persist()
.
Может кто-нибудь объяснить мне это поведение?
Редактировать:
Я даже пытался использовать FlushMode.РУКОВОДСТВО для сеанса гибернации, но оно все равно выполняет ВСТАВКУ после em.persist
. Итак, нет ли способа вручную контролировать, когда выполняется сброс?
Правка2:
Вот проблема, с которой я столкнулся. У меня есть объект A
, который имеет-объект B
. Объект B
еще не существует во время вызова em.persist(a)
, и у меня есть «ПРОВЕРКА ОГРАНИЧЕНИЙ (B НЕ РАВНО NULL) в базе данных». Единственное решение, которое я нашел, — использовать отложенное ограничение в Oracle. Однако это решение зависит от поставщика и на самом деле меня не удовлетворяет.
Каскадное
редактирование 3: кажется хорошим решением, но в нашем проекте нам не разрешено его использовать. Нам рекомендуется вручную управлять всеми вставками и обновлениями.
Комментарии:
1. Чтобы ответить на этот вопрос, может быть полезно узнать, как отображается MyEntity
Ответ №1:
Фиксация в режиме FlushMode не гарантирует, что фиксация произойдет при фиксации транзакции. Это скорее подсказка для поставщика (разработчика спецификаций, например, Hibernate здесь), но он может делать это, когда захочет. Если вы хотите сохранить / обновить компонент, у которого есть новая зависимость, которая еще не существует в базе данных. используйте каскад для операций сохранения / слияния, чтобы также сохранить его. ЕСЛИ вы объявили поле / зависимость как не-nullable, то для JPA нормально не разрешать вам сохранять объект с этим полем / зависимостью null, поскольку он применяет ограничения, которые вы на него накладываете. То, что вы хотите сделать, — это в значительной степени хак / обходной путь вокруг спецификаций JPA. вы либо делаете это поле / зависимость обнуляемыми, если на самом деле оно иногда может быть нулевым, либо вы убедитесь, что оно никогда не равно нулю (и каскадируется, если это новое значение) при сохранении родительского элемента.
Комментарии:
1. Спасибо за ответ! К сожалению, нам не разрешено использовать каскады в нашем проекте. Что касается предложения с нулевым значением. Ну, во-первых, это не обнуляется естественным образом, между этими объектами всегда существует обязательное взаимно однозначное отношение. Но даже если я пометил его как nullable , боюсь, это ничего не изменит, потому что Hibernate выдает инструкцию INSERT в базу данных после вызова em.persist , что, в свою очередь, вызывает ConstraintViolationException .
2. Ну, тогда, я думаю, вы можете попробовать использовать прослушиватель жизненного цикла объекта, который перехватывает объект до его обновления или создания, проверяет, имеет ли он нулевую зависимость, и если это так, он сначала создаст эту необходимую зависимость, сохранит ее и добавит в компонент, а затем разрешит первоначальное обновление/persist продолжить : download.oracle.com/docs/cd/B32110_01/web.1013/b28221 /…
3. Проблема в том, что зависимый объект не может быть создан в этот момент. Я знаю, это может показаться странным, но я работаю над довольно большим проектом, и я не могу изменить рабочий процесс, разработанный нашими архитекторами. Но спасибо за предложение, я постараюсь что-нибудь придумать.
Ответ №2:
Поскольку режим фиксации не гарантирует, что сброс происходит только во время фиксации. Раздел 3.2.4 в спецификации:
Если FlushModeType .Указана ФИКСАЦИЯ, очистка будет происходить при фиксации транзакции; поставщику сохранения разрешено, но не обязательно, выполнять очистку в другое время.
Комментарии:
1. Хорошо, я сам недавно прочитал это. Но тогда какой смысл устанавливать FlushMode, если он не гарантирует, когда произойдет сброс?
2. Я думаю, цель не в том, чтобы строго определять, как выполняется сброс. Речь идет скорее о предоставлении провайдеру возможности (но не о принуждении) к оптимизированной реализации. При запросе через entity manager в режиме COMMIT- flush: видны ли обновления, не указано (поэтому это не гарантирует, что обновления видны / невидимы). Для меня это немного похоже на вызов Integer.valueOf(32768), результат не гарантированно кэшируется, но может быть.
3. Спасибо за ваш вклад. Я подожду некоторое время, если другим есть что сказать по этому поводу. Также см. Редактирование.
Ответ №3:
Из-за спящего режима firstlevelcache