Как решить исключение" не удалось лениво инициализировать коллекцию ролей " Hibernate



у меня такая проблема:




орг.зимовать.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 цикл

1288   26  

26 ответов:

если вы знаете, что вы хотите видеть все Comments каждый раз, когда вы получаете Topic затем измените отображение поля на comments to:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

коллекции лениво загружаются по умолчанию, взгляните на этой если вы хотите знать больше.

по моему опыту, у меня есть следующие методы для решения знаменитого LazyInitializationException:

(1) Используйте Режим Гибернации.инициализировать

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());

гибернации инициализатора связывает свои занятия в спящий режим технология. Если вы стремитесь быть гибким-это не лучший способ пойти.

надеюсь, что это помогает

причина в том, что при использовании отложенной загрузки сеанс закрывается.

есть два решения.

  1. не использовать отложенную загрузку.

    Set lazy=false в XML или Set @OneToMany(fetch = FetchType.EAGER) в аннотации.

  2. использовать отложенную загрузку.

    Set lazy=true в XML или Set @OneToMany(fetch = FetchType.LAZY) В аннотации.

    и добавить OpenSessionInViewFilter filter в своем web.xml

подробно смотрите мой POST.

для ленивой загрузки коллекции должен быть активный сеанс. В веб-приложении есть два способа сделать это. Вы можете использовать Открыть Сеанс В Вид шаблон, где вы используете перехватчик открыть сеанс в начале запроса и закрыть его в конце. Существует риск, что вы должны иметь надежную обработку исключений, или вы можете связать все свои сеансы, и ваше приложение может зависнуть.

другой способ справиться с этим - соберите все необходимые данные в контроллере, закройте сеанс, а затем поместите данные в свою модель. Я лично предпочитаю этот подход, так как он кажется немного ближе к духу шаблона MVC. Кроме того, если вы получаете сообщение об ошибке из базы данных таким образом, вы можете справиться с этим намного лучше, чем если бы это произошло в вашем рендере представления. Ваш друг в этом сценарии спящий режим.инициализировать(раздел mytopic.getComments()). Вам также придется повторно присоединить объект к сеансу, так как вы создаете новую транзакцию с каждым запросом. Используйте сеанс.lock (myTopic,LockMode.Нет) для этого.

проблема вызвана доступом к атрибуту с закрытым сеансом hibernate. У вас нет транзакции гибернации в контроллере.

возможные решения:

  1. сделайте всю эту логику, в сервисном слое, (С @Transactional), не в контроллере. Должно быть правильное место для этого, это часть логики приложения, а не в контроллере (в данном случае интерфейс для загрузки модели). Все операции в сервисном слое должен быть транзакционный. т. е.: переместите эту строку в TopicService.метод findTopicByID:

    коллекция commentList = topicById.getComments();

  2. используйте "нетерпеливый" вместо "ленивый". Теперь вы не используете "ленивый".. это не реальное решение, если вы хотите использовать ленивый, работает как временное (очень временное) решение.

  3. используйте @Transactional в контроллере. Его не следует использовать здесь вы смешиваете сервисный слой с презентацией, это не очень хороший дизайн.
  4. использовать OpenSessionInViewFilter, сообщается о многих недостатках, возможной нестабильности.

в общем, лучшим решением является 1.

@Controller
@RequestMapping(value = "/topic")
@Transactional

Я решаю эту проблему, добавляя @Transactional, Я думаю, что это может сделать сессию открытой

Если вы пытаетесь установить связь между сущностью и коллекцией или списком объектов java (например, Long type), он хотел бы что-то вроде этого:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;

я узнал, что объявление @PersistenceContext как EXTENDED также решает эту проблему:

@PersistenceContext(type = PersistenceContextType.EXTENDED)

@ транзакционная аннотация на контроллере отсутствует

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}

Это была проблема, с которой я недавно столкнулся, которую я решил с помощью

<f:attribute name="collectionType" value="java.util.ArrayList" />

более подробное описание здесь и это спасло мой день.

ваш список лениво загружается, поэтому список не был загружен. звоните, чтобы попасть в список недостаточно. используйте в спящем режиме.инициализации для инициализации списка. Если и работать на элемент списка и звоните гибернации.инициализировать для каждого . это должно быть до того, как вы вернетесь из области транзакции. посмотри на этой пост.
ищите -

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" />

в файле контекста приложения.

The @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

вы всегда должны избегать следующих анти-паттернов:

поэтому убедитесь, что это ваш FetchType.LAZY ассоциации инициализируются во время запроса или в исходном @Transactional объем, используя Hibernate.initialize для вторичной коллекций.

С помощью гибернации @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 proxy-управляемой транзакции, факт вызова ticket.getSales() сделайте еще один запрос, чтобы получить продажи, потому что вы явно попросили его.

причина в том, что вы пытаетесь получить список комментариев на своем контроллере после закрытия сеанса внутри службы.

topicById.getComments();

выше будет загружать список комментариев только в том случае, если ваш сеанс hibernate активен, который, я думаю, вы закрыли в своем сервисе.

Итак, вы должны получить список комментариев перед закрытием сессии.

в моем cae у меня было отображение b / w A и B как

а

@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;

в слое DAO,метод должен быть аннотирован @Transactional Если вы не аннотировали отображение с помощью Fetch Type-Eager

коллекция 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

решение может быть:

  1. аннотации comments С fetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
    
  2. если вы все еще хотите, чтобы комментарии были лениво загружены, используйте сеансы гибернации с сохранением состояния, так что вы сможете получить комментарии позже по требованию.

Привет всем проводка довольно поздно, надеюсь, что это помогает другим, Заранее благодарим @GMK за этот пост спящий режим.инициализировать(объект)

когда 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 " даже после закрытия сеанса гибернации.

одним из лучших решений является добавление в приложение следующего.файл свойств: весна.СПД.свойства.зимовать.enable_lazy_load_no_trans=true

еще один способ, чтобы сделать это, вы можете использовать TransactionTemplate чтобы обернуть вокруг ленивой выборки. Как

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>();

Comments

    Ничего не найдено.