Я столкнулся с проблемой ленивой инициализации, когда добавил проект Lombok в свой проект гибернации и использовал его @Getter
и @Setter
в классе сущности.
Классы сущностей аннотированы @Entity
Javax.persistence, поскольку я использую hibernate 5.
Проблема с трассировкой стека: -
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:146)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:259)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
at com.capehenry.domain.user.User_$$_jvst52e_9.getId(User_$$_jvst52e_9.java)
at com.capehenry.business.rs.course.SeatRequestResource.validateSeatRequestCancel(SeatRequestResource.java:338)
at com.capehenry.business.rs.course.SeatRequestResource.cancel(SeatRequestResource.java:220)
Все работало нормально с приведенным ниже кодом
@Entity
@Audited
@Table(name = "seat_request")
public class SeatRequest extends BaseEntity {
private CourseSchedule courseSchedule;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "courseScheduleId", nullable = false)
public CourseSchedule getCourseSchedule() {
return courseSchedule;
}
public void setCourseSchedule(CourseSchedule courseSchedule) {
this.courseSchedule = courseSchedule;
}
Когда я выполняю searchRequest.getCourseSchedule (). GetId (), он работает в состоянии покоя вне транзакции.
Как только я изменяю код на приведенный ниже (добавляю ломбок), searchRequest.getCourseSchedule (). GetId () на уровне покоя начинает выбрасывать lazyInitializationException: -
@Entity
@Audited
@Table(name = "seat_request")
@Setter
public class SeatRequest extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY, optional=false)
@JoinColumn(name = "courseScheduleId", nullable = false)
private CourseSchedule courseSchedule;
ПРИМЕЧАНИЕ :-
1) У меня обязательно использовать Lombok project
2) Мне нужно использовать searchRequest.getCourseSchedule (). GetId () вне Sevrice и trasaction
Пожалуйста, предложите решение, заранее спасибо!
I have to use searRequest.getCourseSchedule().getId() outside Service and transaction
Я заметил это только что ... Если вы находитесь за пределами службы и транзакции, у вас всегда будет это исключение. Попробуйте использовать FetchType.EAGER
и он должен работать.
Когда вы находитесь вне транзакции, ваши сущности отсоединяются, это означает, что все коллекции, которые вы пометили как ленивые, не будут загружены. Таким образом, у вас есть два варианта: первый - выполнить все вызовы геттеров коллекций внутри транзакции, второй - пометить вашу коллекцию как готовую, поэтому, когда Hibernate загружает объект, он также немедленно загружает указанную коллекцию. В качестве альтернативы вы можете сопоставить DTO свою сущность внутри транзакции. Пока вы находитесь в транзакции, получатели ленивого загруженного поля всегда будут работать, поэтому преобразователь в DTO будет иметь доступ ко всей информации. Как только DTO выйдет из транзакции, у вас будет доступ ко всем полям, которые вы сопоставили, и вы сможете делать все, что захотите.
Спасибо за быстрый ответ .. Я уже использовал FethcType.LAZY. И меня беспокоит то, что он работал раньше ... Я добавил свой старый код, поскольку я пропустил, что у меня были аннотации к методу получения, а не на уровне поля, пока он работал вне транзакции.
Вы пробовали использовать аннотации для полей без ломбока?
нет .. Я собирался это сделать .. но пока нашел эту ссылку stackoverflow.com/questions/2593722/… Итак, теперь пытаюсь получить доступ type = property
Сообщите нам, если это поможет
Я нашел решение .. поставлю как ответ на этот вопрос .. Спасибо за помощь @Lore
Я заметил, что сделал ошибку: я имел в виду EAGER, а не LAZY при аннотации FetchType. Однако как вы ее решили?
Я добавил решение как ответ на этот вопрос
Вот как я наконец решил проблему!
Я думал, что проблема началась после интеграции с проектом Lombok, но проблема началась, когда аннотации были перемещены на уровень поля с уровня метода (свойства).
Потерпите длинный ответ.
Здесь foreign относится к сторонним таблицам уровня базы данных.
Чтобы получить доступ к любому столбцу из вне сделки сторонней таблицы, вам нужно либо использовать FetchType.Eager (который по умолчанию находится в спящем режиме для любого постороннего объекта), либо необходимо присоединиться / запросить эту таблицу.
Но если вы просто хотите получить внешний ключ (столбец), с которым объединены 2 таблицы (в нашем случае идентификатор), и хотите сохранить FetchType.LAZY, вы можете сделать это двумя способами: -
1) Сохраняйте аннотации (manyToOne, JoinColumn и т. д.) В методах получения
2) Если аннотации должны храниться в полевой уровень, тогда напишите еще одну аннотацию в поле внешнего ключа в родительской таблице, которая является - @ Доступ (AccessType.PROPERTY) Итак, в приведенном выше коде для решения я добавил эту аннотацию в поле id, конечно, Расписание
@Entity
@Audited
@Table(name = "course_schedule")
@Getter
@Setter
public class CourseSchedule{
@Id
@GenericGenerator(name = "autoincr", strategy = "native")
@GeneratedValue(generator = "autoincr")
@Column(name = "id", unique = true, nullable = false)
@Access(AccessType.PROPERTY)
protected Long id;
..........
}
Таким образом, никаких изменений в запросе места не потребовалось.
Так почему бы просто EAGER не получить идентификатор? Ленивая выборка, как правило, является хорошей стратегией для вещей, которые вам не обязательно нужны постоянно, поле идентификатора достаточно важно, чтобы просто получать данные с нетерпением.