Как решить" не удалось лениво инициализировать коллекцию роли " Hibernate исключение
у меня такая проблема:
org.зимовать.LazyInitializationException: не лениво инициализировать коллекция роль: mvc3.модель.Тема.комментарии, ни одна сессия или сессия не была закрыта
вот модели:
@Entity
@Table(name = "T_TOPIC")
public class Topic {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@ManyToOne
@JoinColumn(name="USER_ID")
private User author;
@Enumerated(EnumType.STRING)
private Tag topicTag;
private String name;
private String text;
@OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
...
public Collection<Comment> getComments() {
return comments;
}
}
контроллер, который вызывает модель, выглядит следующим образом:
@Controller
@RequestMapping(value = "/topic")
public class TopicController {
@Autowired
private TopicService service;
private static final Logger logger = LoggerFactory.getLogger(TopicController.class);
@RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
public ModelAndView details(@PathVariable(value="topicId") int id)
{
Topic topicById = service.findTopicByID(id);
Collection<Comment> commentList = topicById.getComments();
Hashtable modelData = new Hashtable();
modelData.put("topic", topicById);
modelData.put("commentList", commentList);
return new ModelAndView("/topic/details", modelData);
}
}
jsp-страница выглядит следующим образом:
<%@page import="com.epam.mvc3.helpers.Utils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>View Topic</title>
</head>
<body>
<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>
</c:forEach>
</ul>
</body>
</html>
исключение rised, при просмотре jsp. В соответствии с c: forEach цикл
26 ответов
если вы знаете, что вы хотите видеть все Comment
s каждый раз, когда вы получаете Topic
затем измените отображение поля на comments
в:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
коллекции ленивы-загружаются по умолчанию, взгляните на этой если вы хотите знать больше.
из моего опыта у меня есть следующие методы для решения знаменитого LazyInitializationException:
(1) Используйте Hibernate.инициализировать
Hibernate.initialize(topics.getComments());
(2) Используйте JOIN FETCH
вы можете использовать синтаксис JOIN FETCH в JPQL для явного извлечения дочерней коллекции. Это как-то похоже на нетерпеливое притягивание.
(3) Использовать OpenSessionInViewFilter
LazyInitializationException часто происходят в слое представления. Если вы используете Spring framework, вы можете использовать OpenSessionInViewFilter. Однако я не предлагаю вам этого делать. Это может привести к проблеме производительности, если не использовать правильно.
происхождение вашей проблемы:
по умолчанию hibernate лениво загружает коллекции (отношения), что означает, когда вы используете collection
в коде(здесь
Я знаю, это старый вопрос, но я хочу помочь. Вы можете поместить транзакционную аннотацию на нужный вам метод обслуживания, в этом случае findTopicByID (id) должен иметь
@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
более подробную информацию об этой аннотации можно найти здесь
о других решениях:
fetch = FetchType.EAGER
не является хорошей практикой, ее следует использовать только в случае необходимости.
Hibernate.initialize(topics.getComments());
инициализатор hibernate связывает ваши классы с hibernate технология. Если вы стремитесь быть гибким-это не лучший способ пойти.
надеюсь, что это помогает
причина в том, что при использовании lazy load сеанс закрывается.
есть два решения.
-
не использовать отложенную загрузку.
Set
lazy=false
в XML или Set@OneToMany(fetch = FetchType.EAGER)
в аннотации. -
использовать отложенную загрузку.
Set
lazy=true
в XML или Set@OneToMany(fetch = FetchType.LAZY)
В аннотации.и добавить
OpenSessionInViewFilter filter
в своемweb.xml
подробно см. Мой в должности.
для ленивой загрузки коллекции должен быть активный сеанс. В веб-приложении есть два способа сделать это. Вы можете использовать Открыть Сеанс В View шаблон, где вы используете перехватчик открыть сеанс в начале запроса и закрыть его в конце. Риск заключается в том, что вы должны иметь надежную обработку исключений, или вы можете связать все свои сеансы, и ваше приложение может зависнуть.
другой способ справиться с этим - соберите все необходимые данные в контроллере, закройте сеанс, а затем вставьте данные в модель. Я лично предпочитаю этот подход, поскольку он кажется немного ближе к духу шаблона MVC. Кроме того, если вы получаете ошибку из базы данных таким образом, вы можете справиться с ней намного лучше, чем если это происходит в вашем представлении. Ваш друг в этом сценарии спящий режим.инициализировать(раздел mytopic.getComments()). Вам также придется повторно присоединить объект к сеансу, так как вы создаете новую транзакцию с каждым запросом. Используйте сеанс.lock (myTopic, LockMode.Нет) за это.
проблема вызвана доступом к атрибуту с закрытым сеансом гибернации. У вас нет транзакции hibernate в контроллере.
возможные решения:
-
сделайте всю эту логику, на уровне сервиса, (С @Transactional), не в контроллере. Должно быть правильное место для этого, это часть логики приложения, а не в контроллере (в данном случае интерфейс для загрузки модели). Все операции на уровне сервиса должна быть транзакционная. т. е.: переместите эту строку в TopicService.метод findTopicByID:
коллекция commentList = topicById.getComments();
используйте "нетерпеливый" вместо "ленивый". Теперь вы не используете "ленивый".. это не реальное решение, если вы хотите использовать ленивый, работает как временное (очень временное) решение.
- используйте @Transactional в контроллере. Его не следует использовать здесь вы смешиваете сервисный слой с презентацией, это не очень хороший дизайн.
- использовать OpenSessionInViewFilter, сообщается о многих недостатках, возможной нестабильности.
в общем, лучшим решением является 1.
@Controller
@RequestMapping(value = "/topic")
@Transactional
Я решаю эту проблему, добавляя @Transactional
, Я думаю, что это может сделать сессию открытой
Если вы пытаетесь иметь отношение между сущностью и коллекцией или списком объектов java( например, Long type), это было бы что-то вроде этого:
@ElementCollection(fetch = FetchType.EAGER)
public List<Long> ids;
я узнал, что объявление @PersistenceContext
as EXTENDED
также решает эту проблему:
@PersistenceContext(type = PersistenceContextType.EXTENDED)
@ транзакционная аннотация на контроллере отсутствует
@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}
Это была проблема, с которой я недавно столкнулся, которую я решил с помощью
<f:attribute name="collectionType" value="java.util.ArrayList" />
более подробное описание здесь и это спасло мой день.
ваш список ленивая загрузка, поэтому список не был загружен.
звоните, чтобы попасть в список недостаточно.
используйте в спящем режиме.инициализации для инициализации списка.
Если dosnt работает, запустите элемент list и вызовите Hibernate.инициализировать для каждого .
это должно быть до того, как вы вернетесь из области транзакции.
посмотреть этой пост.
искать -
Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session
чтобы решить проблему в моем случае, просто не хватало этой строки
<tx:annotation-driven transaction-manager="myTxManager" />
в файле контекста приложения.
на @Transactional
аннотация над методом не учитывалась.
надеюсь, что ответ поможет кому-то
для тех, кто работает с критерии, я обнаружил, что
criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);
сделал все, что нужно, сделал.
начальный режим выборки для коллекций имеет значение FetchMode.Ленивый, чтобы обеспечить производительность, но когда мне нужны данные, я просто добавляю эту строку и наслаждаюсь полностью заполненными объектами.
в моем случае следующий код, проблема:
entityManager.detach(topicById);
topicById.getComments() // exception thrown
потому что он отделился от базы данных и Hibernate больше не извлекал список из поля, когда это было необходимо. Поэтому я инициализирую его перед отсоединением:
Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm
как я объяснил в в этой статье лучший способ обработки LazyInitializationException
должен получить его во время запроса, например:
select t
from Topic t
left join fetch t.comments
вы всегда должны избегать следующих анти-шаблонов:
- сделать ассоциации нетерпеливыми
- использование OSIV (открытая сессия в поле зрения)
- включение
hibernate.enable_lazy_load_no_trans
свойство конфигурации Hibernate
поэтому убедитесь, что это твой FetchType.LAZY
ассоциации инициализируются во время запроса или в исходном @Transactional
объем, используя Hibernate.initialize
для вторичной коллекций.
С помощью hibernate @Transactional
аннотация, если вы получаете объект из базы данных с ленивыми извлеченными атрибутами, вы можете просто получить их, извлекая эти атрибуты следующим образом:
@Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
savedTicketOpt.ifPresent(ticket -> {
Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
assertThat(saleOpt).isPresent();
});
}
здесь, в транзакции, управляемой прокси-сервером Hibernate, факт вызова ticket.getSales()
сделайте еще один запрос для получения продаж, потому что вы явно спросили его.
причина вы пытаетесь получить commentList на геймпаде после закрытия сессии в службе.
topicById.getComments();
выше загрузит список комментариев, только если ваш сеанс гибернации активен, который, я думаю, вы закрыли в своем сервисе.
Итак, вы должны получить список комментариев перед закрытием сеанса.
в моем cae у меня было отображение b / w A и B, как
A имеет
@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;
в слое DAO метод необходимо аннотировать с @Transactional
Если вы не аннотировали отображение с помощью Fetch Type-Нетерпеливый
коллекция comments
в вашем классе моделей Topic
лениво загружается, что является поведением по умолчанию, если вы не аннотируете его с помощью fetch = FetchType.EAGER
специально.
скорее всего, что ваш findTopicByID
служба использует сеанс гибернации без состояния. сеанс без состояния не имеет кэша первого уровня, т. е. без контекста персистентности. Позже, когда вы попытаетесь повторить comments
, Hibernate выдаст исключение.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
решение может быть:
-
аннотации
comments
Сfetch = FetchType.EAGER
@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL) private Collection<Comment> comments = new LinkedHashSet<Comment>();
если вы все еще хотите, чтобы комментарии были лениво загружены, используйте сеансы состояния Hibernate, так что вы сможете получить комментарии позже по требованию.
Привет всем постинг довольно поздно надеюсь, что это поможет другим, Заранее благодарю @GMK за этот пост спящий режим.initialize (object)
когда Lazy= "true"
Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();
теперь, если я получаю доступ к " set " после закрытия сеанса, он выдает исключение.
мое решение :
Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();
теперь я могу получить доступ к " set " даже после закрытия сеанса гибернации.
одним из лучших решений является добавление в приложение следующего.файл свойств: весна.jpa.свойства.зимовать.enable_lazy_load_no_trans=true
еще один способ, чтобы сделать это, вы можете использовать TransactionTemplate обернуть вокруг ленивого fetch. Как
Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());
добавьте это к вашей настойчивости.в XML
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
Я решил использовать List вместо Set:
private List<Categories> children = new ArrayList<Categories>();