Hibernate LazyInitializationException on find () with EIGHTER @ElementCollection
Я получаю org.hibernate.LazyInitializationException: illegal access to loading collection в своем коде JPA - все коллекции стремятся получить - когда объект коллекции также имеет коллекцию.
Не мог бы кто-нибудь помочь мне это исправить?
Я выделил проблему в своем коде JPA следующим определениям @Entity:
(Обратите внимание, я пропускаю инструкции package и import, чтобы сократить код. Некоторые аннотации Ломбока используются, такие как @Data, чтобы означать, что поле имеет геттер / сеттер и @Cleanup, чтобы сделать обычную попытку / перехват закрыть () танец)
@Entity
@Data
public class MyEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// @ElementCollection(fetch = FetchType.EAGER)
// private Set<String> tags = Sets.newTreeSet();
}
@Entity
@Data
public class MyOtherEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
private Set<MyEntity> entities = Sets.newHashSet();
}
(я также получаю ту же проблему, если я явно делаю полный @JoinTable, но Hibernate, кажется, генерирует все прекрасно без него - я счастлив оставить его).
Проблема в том, что если я раскомментирую поле "теги" в @MyEntity, то я всегда получаю следующее PersistenceException
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.LazyInitializationException: illegal access to loading collection
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:828)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:781)
Ниже приводится краткое приложение, которое иллюстрирует эту проблему:
public class JpaQuestion {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("hibernate.connection.driver_class", "org.apache.derby.jdbc.EmbeddedDriver");
properties.put("hibernate.connection.url", "jdbc:derby:playground;create=true");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PlaygroundPU", properties);
populate(emf);
@Cleanup("close") EntityManager em = emf.createEntityManager();
MyOtherEntity other = em.find(MyOtherEntity.class, 1L);
System.out.println(other != null ? other.toString() : "null");
}
public static void populate(EntityManagerFactory emf) {
@Cleanup("close") EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
MyEntity a = new MyEntity();
em.persist(a);
MyOtherEntity other = new MyOtherEntity();
other.getEntities().add(a);
em.persist(other);
em.getTransaction().commit();
}
}
UPDATE: я знаю о LazyInitializationException, когда поле жаждет , но это кажется, потому что load() захватывает ленивую версию сущности. Я использую здесь "найти". Я заметил, что если я выдам запрос JPA (вместо find), то эта проблема исчезнет.
UPDATE: это действительно хорошо работает, если вместо find() я использую запрос типа "SELECT b FROM MyOtherEntity b WHERE b.id = :id". Может быть, find() действительно игнорирует загрузку EAGER! Следовательно, это, скорее всего, ошибка в спящем режиме.
Обновление: я зарегистрировал это как сообщение об ошибке с Hibernate в https://hibernate.onjira.com/browse/HHH-7476
4 ответов:
Прежде всего полезно ссылаться на полную трассировку стека: http://pastie.org/4358203
Проблема вызвана вашим вызовом тегов.hashCode () в реализации hashCode () функции MyEntity.
Когда вы используете Hibernate для загрузки экземпляра MyOtherEntity, инициализируется его коллекция MyEntity. Когда MyEntity добавляется к реализации набора в MyOtherEntity, естественно вызывается метод hashCode () (наборы не могут содержать дубликатов. и hashCode () является частью того, как Java проверяет равенство объектов). Затем метод hashCode () MyEntity пытается вызвать hashCode () в коллекции тегов. Коллекция тегов находится в процессе инициализации, что приводит к этой ошибке.
Я думаю, что стоит подумать о вашей реализации hashCode () для MyEntity. Действительно ли ваш прецедент требует, чтобы вы сравнивали значения всех элементов в коллекции тегов для обеспечения равенства объектов?
Подробнее информация по управлению равенством объектов в режиме гибернации является полезным ресурсом:
LazyInitializationException-указывает на доступ к незафиксированным данным вне контекста сеанса. Например, при обращении к неинициализированному прокси-серверу или коллекции после закрытия сеанса.Некоторые вещи, которые вы, возможно, захотите попробовать:
Снято
@Cleanup- как aLazyInitializationExceptionобычно это означает, что сеанс гибернации был закрыт, Когда прокси-сервер пытался получить доступ к полю, вы должны попробовать это без них@Cleanupаннотации. Я никогда ими не пользовался я сам, но в документах говорится, что объявление переменной очищается вызовом.close()"конец вашей области видимости".Конфигурация двойной проверки - все еще нечетная, поскольку вы объявляете
FetchType.EAGERдля обеих ассоциаций. Вы проверили, что эти варианты действительно используются? Я знаю, что конфигурация иногда может быть немного сложной.PersistenceContextType - вы можете попробовать установить
PersistenceContextType.EXTENDEDдля вашегоEntityManager(я думаю, чтоTRANSACTIONявляется по умолчанию, может быть неправильно но вы можете попробовать быть уверенным).Я думаю, вы уже знаете "LazyInitializationException overcome" запись Вики?
Проблема в том, что Hibernate игнорирует fetch = FetchType.Жаждущий большинства запросов. Попробуйте добавить @Fetch (FetchMode.Присоединиться) к сущностям.
Эта ошибка появляется, когда hibernate пытается инициализировать объект и возникает некоторая ошибка.
Ошибка может быть
- хэш-код и равенства не реализованы должным образом
- Ожидается, что ленивый объект будет зашифрован, но в БД он не зашифрован должным образом
- вы находитесь вне контекста сеанса гибернации.
Comments