Jak rozwiązać wyjątek hibernacji "nie udało się leniwie zainicjować kolekcji ról"

Mam taki problem:

Org.hibernacja.LazyInitializationException: nie udało się leniwie zainicjować kolekcji roli: mvc3.model.Temat.komentarze, Żadna sesja ani sesja nie została zamknięta

Oto model:

@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;
    }

}

Kontroler wywołujący model wygląda następująco:

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

     }

}

Strona jsp wygląda następująco:

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

Wyjątek jest wyświetlany podczas wyświetlania jsp. In the line with c: forEach loop

Author: Vlad Mihalcea, 2012-07-31

26 answers

Jeśli wiesz, że będziesz chciał zobaczyć wszystkie Comment s za każdym razem, gdy odzyskasz Topic, Zmień mapowanie pola dla comments na:

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

Kolekcje są domyślnie ładowane leniwie, spójrz na to jeśli chcesz wiedzieć więcej.

 155
Author: darrengorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:57

Z mojego doświadczenia, mam następujące metody, aby rozwiązać słynny LazyInitializationException:

(1) Użyj Hibernate.initialize

Hibernate.initialize(topics.getComments());

(2) Użyj JOIN FETCH

Możesz użyć składni JOIN FETCH w JPQL, aby jawnie pobrać kolekcję potomną. To jest jak gorliwy aport.

(3) Użyj OpenSessionInViewFilter

LazyInitializationException często występuje w warstwie widoku. Jeśli korzystasz z Spring framework, możesz można użyć OpenSessionInViewFilter. Nie sugeruję jednak, by pan to robił. Może to prowadzić do problemów z wydajnością, jeśli nie jest używane poprawnie.

 136
Author: Boris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-15 11:08:58

Źródło problemu:

Domyślnie hibernate leniwie ładuje zbiory (relacje) co oznacza, że gdy użyjesz collection w swoim kodzie (tutaj comments pole w klasie Topic) hibernate pobiera to z bazy danych, teraz problem polega na tym, że otrzymujesz kolekcję w kontrolerze (gdzie Sesja JPA jest zamknięta).Jest to linia kodu, która powoduje wyjątek (gdzie ładujesz zbiór comments):

    Collection<Comment> commentList = topicById.getComments();

Otrzymujesz " komentarze" kolekcja (temat.getComments()) w kontrolerze(gdzie JPA session zakończył się) i to powoduje wyjątek. Również jeśli masz zbiór comments w pliku jsp w ten sposób (zamiast pobierać go w kontrolerze):

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>
Nadal mielibyście ten sam wyjątek z tego samego powodu.

Rozwiązanie problemu:

Ponieważ możesz mieć tylko dwie kolekcje z FetchType.Eager (encja) w klasie encji i dlatego, że leniwe ładowanie jest bardziej wydajny jeśli nie chcesz, aby twój problem został rozwiązany, skontaktuj się z nami, aby uzyskać więcej informacji.]}

Jeśli chcesz mieć zainicjalizowaną kolekcję lazy, a także sprawić, by ta działała, lepiej dodać ten fragment kodu do swojego web.xml:

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Ten kod powoduje, że zwiększy długość twojego JPA session lub jak mówi dokumentacja, jest używany "to allow for lazy loading in web views despite the original transactions already being completed." więc w ten sposób sesja JPA będzie otwarta nieco dłużej i z tego powodu możesz leniwie ładować kolekcje w plikach jsp i klasach kontrolerów.

 45
Author: gandalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 10:21:22

Wiem, że to stare pytanie, ale chcę pomóc. Możesz umieścić adnotację transakcyjną w metodzie usługi, której potrzebujesz, w tym przypadku findTopicByID (id) powinien mieć

@Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)

Więcej informacji o tej adnotacji można znaleźć tutaj

O innych rozwiązaniach:

fetch = FetchType.EAGER 

Nie jest dobrą praktyką, należy ją stosować tylko wtedy, gdy jest to konieczne.

Hibernate.initialize(topics.getComments());

Inicjalizacja hibernate wiąże Twoje klasy z technologią hibernate. Jeśli chcesz być elastyczny nie jest / align = "left" /

Hope it helps

 34
Author: sarbuLopex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:54

Powodem jest to, że gdy używasz Lazy load, sesja jest zamknięta.

Istnieją dwa rozwiązania.
  1. Nie używaj leniwego obciążenia.

    Ustaw lazy=false W XML lub Ustaw @OneToMany(fetch = FetchType.EAGER) w adnotacji.

  2. Użyj leniwego obciążenia.

    Ustaw lazy=true w XML lub ustaw @OneToMany(fetch = FetchType.LAZY) w adnotacji.

    I dodać OpenSessionInViewFilter filter w swoim web.xml

Szczegóły zobacz mój POST.

 28
Author: saneryee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-24 11:09:37

W celu leniwego załadowania kolekcji musi być aktywna sesja. W aplikacji internetowej można to zrobić na dwa sposoby. Możesz użyć Open Session we wzorze View, gdzie używasz interceptor, aby otworzyć sesję na początku żądania i zamknąć ją na końcu. Istnieje ryzyko, że musisz mieć solidną obsługę wyjątków lub możesz związać wszystkie sesje, a Twoja aplikacja może się zawiesić.

Innym sposobem radzenia sobie z tym jest zebranie wszystkich danych, które potrzebujesz kontrolera, Zamknij sesję, a następnie wepchnij dane do modelu. Osobiście wolę takie podejście, ponieważ wydaje się nieco bliższe duchowi wzorca MVC. Również Jeśli pojawi się błąd z bazy danych w ten sposób można obsłużyć go o wiele lepiej niż jeśli dzieje się to w widoku renderer. Twoim przyjacielem w tym scenariuszu jest Hibernate.initialize (myTopic.getComments ()). Konieczne będzie również ponowne podłączenie obiektu do sesji, ponieważ tworzysz nową transakcję z każdą prośbą. Użyj sesji.zamek (myTopic,LockMode.Brak) za to.

 19
Author: GMK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-02 17:47:20

Problem jest spowodowany uzyskaniem dostępu do atrybutu z zamkniętą sesją hibernate. Nie masz transakcji hibernate w kontrolerze.

Możliwe rozwiązania:

  1. Wykonaj całą tę logikę w warstwie usług (z @Transactional), a nie w kontrolerze. Powinno być odpowiednie miejsce, aby to zrobić, jest to część logiki aplikacji, a nie w kontrolerze (w tym przypadku interfejs do Ładowania Modelu). Wszystkie operacje w warstwie usług powinny bądź transakcyjny. tj.: przenieś tę linię do serwisu TopicService.metoda findTopicByID:

    Collection commentList = topicById.getComments ();

  2. Użyj 'eager' zamiast 'lazy' . Teraz nie używasz "leniwego".. nie jest to realne rozwiązanie, jeśli chcesz korzystać z leniwego, działa jak tymczasowe (bardzo tymczasowe)obejście.

  3. użyj @Transactional w kontrolerze . Nie powinien być tutaj używany, mieszasz warstwę usług z prezentacją, nie jest to dobre design.
  4. użyj OpenSessionInViewFilter , wiele wad zgłoszonych, możliwa niestabilność.

Ogólnie najlepszym rozwiązaniem jest 1.

 14
Author: abentan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-13 14:17:16
@Controller
@RequestMapping(value = "/topic")
@Transactional

Rozwiązuję ten problem dodając @Transactional, myślę, że może to spowodować otwarcie sesji

 13
Author: RuiZhi Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-10 16:36:50

Jeśli próbujesz mieć relację między encją a kolekcją lub listą obiektów java( na przykład Long type), to chcesz coś takiego:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;
 10
Author: javaboygo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 14:50:11

Dowiedziałem się, że deklarowanie @PersistenceContext jako EXTENDED również rozwiązuje ten problem:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
 9
Author: Elcin ABD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-16 13:22:12

@Brak adnotacji transakcyjnej na kontrolerze

@Controller
@RequestMapping("/")
@Transactional
public class UserController {
}
 6
Author: Xcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-26 10:30:47

To był problem, z którym ostatnio się spotkałem, który rozwiązałem używając

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

Bardziej szczegółowy opis tutaj i to uratowało mój dzień.

 5
Author: tolgayilmaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 15:22:57

Twoja lista jest leniwa, więc lista nie została załadowana. wezwanie, aby dostać się na Listę nie wystarczy. użyj w Hibernate.inicjalizuj w celu init listy. Jeśli praca dosnt zostanie uruchomiona na elemencie list i wywoła Hibernate.inicjalizuj dla każdego . musi to nastąpić przed powrotem z zakresu transakcji. spójrz na ten post.
Szukaj -

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 
 5
Author: Avihai Marchiano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-24 11:24:30

Aby rozwiązać problem w moim przypadku brakowało tylko tej linii

<tx:annotation-driven transaction-manager="myTxManager" />

W pliku application-context.

Adnotacja @Transactional nad metodą nie została uwzględniona.

Mam nadzieję, że odpowiedź pomoże komuś

 4
Author: Mario Biasi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-05 16:38:38

Dla osób pracujących z kryteriami , stwierdziłem, że

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);
Zrobiłem wszystko, czego potrzebowałem.

Początkowy tryb pobierania dla kolekcji jest ustawiony na FetchMode.Leniwy, aby zapewnić wydajność, ale gdy potrzebuję danych, po prostu dodać tę linię I cieszyć się w pełni zaludnionych obiektów.

 2
Author: velis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-01 05:22:43

W moim przypadku następujący kod był problemem:

entityManager.detach(topicById);
topicById.getComments() // exception thrown

Ponieważ odłączył się od bazy danych i Hibernate nie pobierał już listy z pola, gdy była potrzebna. Więc inicjalizuję go przed odłączeniem:

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm
 2
Author: kiedysktos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 09:36:53

Jak wyjaśniłem w Ten artykuł , najlepszym sposobem obsługi LazyInitializationException jest pobranie go w czasie zapytania, Tak:

select t
from Topic t
left join fetch t.comments

Należy zawsze unikać następujących anty-wzorców:

Dlatego upewnij się, że Twoje skojarzenia FetchType.LAZY są inicjowane w czasie zapytania lub w oryginalny @Transactional Zakres wykorzystujący Hibernate.initialize dla zbiorów drugorzędnych.

 2
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-27 06:21:50

Używając adnotacji hibernate @Transactional, Jeśli otrzymasz obiekt z bazy danych z leniwie pobieranymi atrybutami, możesz je po prostu uzyskać, pobierając te atrybuty w następujący sposób:

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

Tutaj, w transakcji zarządzanej przez proxy Hibernate, fakt wywołania ticket.getSales() wykonaj kolejne zapytanie, aby pobrać sprzedaż, ponieważ wyraźnie o to zapytałeś.

 2
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-25 11:59:54

Powodem jest to, że próbujesz uzyskać listę komentarzy na kontrolerze po zamknięciu sesji w usłudze.

topicById.getComments();

Powyżej załaduje się lista komentarzy tylko wtedy, gdy Twoja sesja hibernate jest aktywna, którą chyba zamknąłeś w swoim serwisie.

Musisz więc uzyskać listę komentarzy przed zamknięciem sesji.

 0
Author: aditya lath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 10:11:10

W moim cae miałem mapowanie b / W A i B jak

A ma

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

W warstwie DAO, metoda musi być opatrzona adnotacją @Transactional, jeśli mapowanie nie zostało opatrzone adnotacją Fetch Type-Eager

 0
Author: Shirgill Farhan Ansari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-23 10:12:58

Kolekcja comments w klasie modelu Topic jest ładowana leniwie, co jest domyślnym zachowaniem, jeśli nie dodasz jej konkretnie fetch = FetchType.EAGER.

Jest bardzo prawdopodobne, że Twoja usługa findTopicByID używa bezstanowej sesji hibernacji. Sesje bezstanowe nie mają bufora pierwszego poziomu, tzn. nie mają kontekstu trwałości. Później, gdy spróbujesz iteracji comments, Hibernate wyrzuci wyjątek.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed

Rozwiązaniem może być:

  1. Przypisy comments z fetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
    
  2. Jeśli nadal chcesz, aby komentarze były leniwie ładowane, użyj sesji stanowych Hibernate , aby móc pobierać komentarze później na żądanie.

 0
Author: Yuci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-20 10:32:18

Witam wszystkich postujących dość późno mam nadzieję, że pomaga innym, Z góry dziękuję @GMK za ten post Hibernate.initialize (object)

When Lazy= "true"

Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();

Teraz, jeśli uzyskam dostęp do ' set ' po zamknięciu sesji, rzuca wyjątek.

Moje rozwiązanie:

Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();

Teraz mam dostęp do ' set ' nawet po zamknięciu sesji Hibernate.

 0
Author: vic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-25 06:41:48

Jednym z najlepszych rozwiązań jest dodanie do aplikacji następujących elementów.Plik Właściwości: Wiosna.jpa.właściwości.hibernacja.enable_lazy_load_no_trans=true

 0
Author: sreekmatta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-01 23:24:38

Jeszcze innym sposobem, możesz użyć TransactionTemplate , aby owinąć leniwy fetch. Jak

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());
 0
Author: aristotll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-01 17:43:50

Dodaj to do swojej wytrwałości.xml

<property name="hibernate.enable_lazy_load_no_trans" value="true" />
 -1
Author: Mohammad-Hossein Jamali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-10 20:03:27

Rozwiązałem używając listy zamiast Set:

private List<Categories> children = new ArrayList<Categories>();
 -8
Author: SaganTheBest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-08 08:42:06