"역할 컬렉션을 느리게 초기화하지 못했습니다"Hibernate 예외를 해결하는 방법


363

이 문제가 있습니다.

org.hibernate.LazyInitializationException : 역할 콜렉션을 지연 초기화하지 못했습니다 : mvc3.model.Topic.comments, 세션 또는 세션이 닫히지 않았습니다.

모델은 다음과 같습니다.

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

jsp를 볼 때 예외가 발생합니다. c : forEach 루프가 있는 라인에서

답변:


214

Comment검색 할 때마다 모든 것을보고 싶다면 Topic필드 매핑을 다음으로 변경하십시오 comments.

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

컬렉션은 기본적으로 느리게로드됩니다 . 자세한 내용을 보려면 이 항목을 살펴보십시오 .


35
죄송하지만 지연로드를 사용하고 싶습니다. 그래서 'LinkedHashSet'유형을 'PersistentList'로 변경했습니다. 예외는 여전히 발생
Eugene

242
이 문제를 해결 방법으로 사용할 수 있지만 실제 문제 해결 방법은 아닙니다. 느리게 가져와야 할 경우 어떻게해야합니까?
Dkyc

14
그러나 우리가 게으른 것을 원한다면이 솔루션은 효과가 없으며 대부분의 경우 게으른 것을 원합니다.
prashant thakre

103
이것은 스택 오버플로의 어느 곳에서나 나타나는 응답 유형입니다. 요컨대, 문제와 MISLEADING을 해결합니다. 미래의 독자들에게 자신에게 호의를 베풀고 정확하게 게으르고 열심히 가져온 것을 배우고 그 결과를 이해하십시오.
Ced

13
@darrengorman JPA를 시작할 때 OP의 행 주위에 질문을 게시했습니다. 당신이 준 것과 같은 응답을 받았습니다. 곧 수십만 행으로 테스트를 실행했을 때 무슨 일이 있었는지 추측하십시오. 나는 초보자가 직면하게되는 문제에 대해 너무 간단한 대답을 제공하기 때문에 잘못 생각한다고 생각합니다. 심지어 조심하지 않으면 메모리에 전체 데이터베이스가로드 될 것입니다. 주의하십시오) :).
Ced

182

내 경험상 유명한 LazyInitializationException을 해결하기 위해 다음과 같은 방법이 있습니다.

(1) 최대 절전 모드를 사용하십시오.

Hibernate.initialize(topics.getComments());

(2) JOIN FETCH 사용

JPQL에서 JOIN FETCH 구문을 사용하여 하위 콜렉션을 명시 적으로 페치 할 수 있습니다. EAGER 페칭과 같은 방식입니다.

(3) OpenSessionInViewFilter 사용

뷰 레이어에서 LazyInitializationException이 자주 발생합니다. Spring 프레임 워크를 사용하는 경우 OpenSessionInViewFilter를 사용할 수 있습니다. 그러나 나는 당신에게 그렇게 제안하지 않습니다. 올바르게 사용하지 않으면 성능 문제가 발생할 수 있습니다.


5
(1) 나를 위해 완벽하게 일했습니다. 내 경우 : Hibernate.initialize (registry.getVehicle (). getOwner (). getPerson (). getAddress ());
Leonel Sanches da Silva

6
Hibernate.initialize는 EntityManager와 작동하지 않는 것 같습니다
marionmaiden

8
이것이 정답이어야합니다. 예를 들어 직장 내 프로젝트에서 EAGER 페칭을 사용해서는 안됩니다. 이 특정 시스템에서 문제가 발생합니다.
Steve Waters

매력적이긴하지만 다른 경우에는 구현할 문서가없는 것 같습니다 ...이 솔루션을 구현하는 방법에 대한 추가 링크 나 설명을 제공해 주시겠습니까?
Pipo

58

나는 그것이 오래된 질문이라는 것을 알고 있지만 도와주고 싶습니다. 필요한 서비스 메소드에 트랜잭션 주석을 넣을 수 있습니다.이 경우 findTopicByID (id)는

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

이 주석에 대한 자세한 내용은 여기를 참조하십시오.

다른 솔루션 정보 :

fetch = FetchType.EAGER 

좋은 습관이 아니므로 필요한 경우에만 사용해야합니다.

Hibernate.initialize(topics.getComments());

최대 절전 모드 초기화 프로그램은 클래스를 최대 절전 모드 기술에 바인딩합니다. 융통성을 목표로하는 것이 좋은 방법은 아닙니다.

그것이 도움이되기를 바랍니다.


3
@Transactional 주석은 저에게 효과적이지만 최소한 Spring Boot 1.4.2 (Spring 4.3)에서는 Propagation.REQUIRED가 기본값입니다.
ben3000

4
네, 그것은,하지만 난 당신이 실제로 전파 PARAM을 변경할 수 있습니다 취소하게 이해할 수 있다고 생각
sarbuLopex

아닌가 @Transactional스프링 - 유일한 방법은?
Campa

@Campa 그렇습니다. 수동으로 처리하려면 비즈니스 관리자를 엔티티 관리자에서 검색 한 트랜잭션 안에 넣어야합니다
sarbuLopex 10

54

문제의 기원 :

기본적으로 최대 절전 모드는 컬렉션 (관계)을 느리게로드합니다. 즉 collection, 코드 comments에서 Topic클래스 (여기서는 필드의 필드 )를 사용할 때마다 최대 절전 모드가 데이터베이스에서 가져옵니다. 이제 문제는 컨트롤러 (JPA 세션이있는 곳)에서 컬렉션을 가져 오는 것입니다 이것은 예외를 발생시키는 코드 줄입니다 ( comments컬렉션을 로드하는 위치 ).

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

컨트롤러 ( JPA session종료 된 곳)에 "comments"컬렉션 (topic.getComments ()) 이 발생하여 예외가 발생합니다. 또한 comments컨트롤러에서 가져 오는 대신 다음과 같이 jsp 파일에 컬렉션 이있는 경우 :

<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>

같은 이유로 여전히 동일한 예외가 있습니다.

문제 해결 :

FetchType.EagerEntity 클래스에서 (열심히 가져온 컬렉션)으로 두 개의 컬렉션 만 가질 수 있고 지연 로딩이 열망 로딩보다 효율적이기 때문에 문제를 해결하는이 방법은 FetchType열망으로 변경하는 것보다 낫습니다 .

컬렉션 지연을 초기화 하고이 작업을 수행하려면 다음 코드를 코드에 추가하는 것이 좋습니다 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>

이 코드는 JPA 세션이 조금 더 길어지고 JSP 파일 및 컨트롤러 클래스에 컬렉션을 느리게로드 할 수 있도록 JPA session사용 "to allow for lazy loading in web views despite the original transactions already being completed."되므로 문서 길이가 길어 지거나 설명서에 명시된 것처럼 사용됩니다 .


7
JPS 세션이 폐쇄 된 이유는 무엇입니까? 닫히지 않는 방법? 게으른 수집을 수행하는 방법?
Dims

1
엔티티 당 두 개의 FetchType.Eager 컬렉션의 제한을 정의하는 것은 무엇입니까?
chrisinmtown

Spring Boot에서 'spring.jpa.open-in-view = true'를 'application.properties'에 추가 할 수 있습니다
Askar

28

지연로드를 사용하면 세션이 닫히기 때문입니다.

두 가지 해결책이 있습니다.

  1. 게으른 하중을 사용하지 마십시오.

    설정 lazy=falseXML 또는 설정에서 @OneToMany(fetch = FetchType.EAGER)에서 주석.

  2. 게으른 하중을 사용하십시오.

    설정 lazy=trueXML 또는 설정에서 @OneToMany(fetch = FetchType.LAZY)에서 주석.

    그리고 OpenSessionInViewFilter filter당신의 추가web.xml

세부 내 POST 참조하십시오 .


1
...하지만 두 솔루션 모두 좋지 않습니다. EAGER를 사용하면 큰 문제가 발생할 수 있습니다. OpenSessionInViewFilter 사용은 안티 패턴입니다.
Rafael

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

추가 하여이 문제를 해결합니다.이 @Transactional세션을 열 수 있다고 생각합니다.


왜 이것이 마이너스 투표를 받았습니까? 작업에 트랜잭션을 추가하면 세션이 연장됩니다
Tudor Grigoriu

1
@Transactional을 컨트롤러에 광고하는 것은 좋지 않습니다.
Rafael

@Rafael 왜 나쁜 연습입니까?
Amr Ellafy

@AmrEllafy-> 여기 좋은 설명이 있습니다 : stackoverflow.com/a/18498834/1261162
Rafael

22

최대 절전 모드 세션이 닫힌 상태에서 속성에 액세스하면 문제가 발생합니다. 컨트롤러에 최대 절전 모드 트랜잭션이 없습니다.

가능한 해결책:

  1. 컨트롤러가 아닌 서비스 계층 (@Transactional 사용) 에서이 모든 논리 를 수행하십시오. 이 작업을 수행 할 올바른 위치가 있어야합니다. 컨트롤러가 아닌 앱의 논리의 일부입니다 (이 경우 모델을로드하는 인터페이스). 서비스 계층의 모든 작업은 트랜잭션 방식이어야합니다. 즉,이 행을 TopicService.findTopicByID 메소드로 이동하십시오.

    컬렉션 commentList = topicById.getComments ();

  2. 'lazy'대신 'eager'를 사용하십시오 . 이제는 'lazy'를 사용하지 않습니다. 게으른 사용하려는 경우 실제 해결책이 아닙니다. 임시 (매우 일시적인) 해결 방법처럼 작동합니다.

  3. 컨트롤러에서 @Transactional을 사용하십시오 . 여기서는 사용하지 말아야합니다. 서비스 계층과 프레젠테이션을 혼합하는 중입니다. 좋은 디자인이 아닙니다.
  4. OpenSessionInViewFilter를 사용 하면 많은 단점이보고되어 불안정성이 발생할 수 있습니다.

일반적으로 가장 좋은 솔루션은 1입니다.


2
페치 유형의 Eager는 최대 절전 모드가 첫 번째 쿼리에서 모든 데이터를
가져 오는

BEST SOLUTION이 1이라는 사실을 대문자로 사용해야합니다 ... 실제로는 다른 모든 것이 안티 패턴이기 때문에 유일한 솔루션입니다!
Rafael

19

컬렉션을 지연로드하려면 활성 세션이 있어야합니다. 웹앱에는 두 가지 방법이 있습니다. 당신이 사용할 수있는 오픈 세션에서보기 당신이 사용 패턴, 인터셉터를 요청의 시작 부분에 세션을 열고 말을 닫습니다합니다. 확실한 예외 처리가 필요하거나 모든 세션을 바인딩 할 수 있고 앱이 중단 될 위험이 있습니다.

이를 처리하는 다른 방법은 컨트롤러에 필요한 모든 데이터를 수집하고 세션을 닫은 다음 데이터를 모델에 채우는 것입니다. MVC 패턴의 정신에 조금 더 가깝기 때문에 개인적 으로이 접근법을 선호합니다. 또한 데이터베이스에서 오류가 발생하면 뷰 렌더러에서 발생하는 것보다 훨씬 잘 처리 할 수 ​​있습니다. 이 시나리오의 친구는 Hibernate.initialize (myTopic.getComments ())입니다. 모든 요청에 ​​대해 새 트랜잭션을 작성하므로 오브젝트를 세션에 다시 첨부해야합니다. 이를 위해 session.lock (myTopic, LockMode.NONE)을 사용하십시오.


15

이 기사 에서 설명했듯이 를 처리하는 가장 좋은 방법 LazyInitializationException은 쿼리 시간에 다음과 같이 가져 오는 것입니다.

select t
from Topic t
left join fetch t.comments

다음과 같은 안티 패턴은 항상 피해야합니다.

따라서 FetchType.LAZY조회시 또는 보조 콜렉션에 @Transactional사용하여 원래 범위 내에서 연관이 초기화 되었는지 확인하십시오 Hibernate.initialize.


1
Vlad 스프링 생성 저장소의 findById () 메소드에 의해 가져온 엔티티에서 지연 초기화 콜렉션 작업에 대한 제안 사항이 있습니까? 쿼리를 작성하지 않고 트랜잭션이 코드 외부에 있습니다.
chrisinmtown

지연 수집 초기화에 대한 자세한 내용은 이 문서 를 확인하십시오 .
Vlad Mihalcea

'원래 @Transactional 범위 내에서'가 의미하는 바를 명확하게
설명해 주

범위 내에서 트랜잭션 게이트웨이라고도하는 최상위 트랜잭션 서비스 방법입니다. TrassctionInterceptor스택 추적에서를 확인하십시오 .
Vlad Mihalcea

지금까지 가장 좋은 답변 중 하나입니다 ...이 올바른 것으로 표시되어야합니다. BTW ... OSIV가 안티 패턴이라고 가정하면 스프링 부트 최신 버전에서 기본적으로 활성화되는 방법은 무엇입니까? ... 나쁘지 않습니까?
Rafael

10

엔터티와 Collection 또는 java 객체 목록 (예 : Long 유형) 사이에 관계를 설정하려는 경우 다음과 같이됩니다.

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

1
많은 경우에, 당신은 정말로 그렇게하고 싶지 않습니다. 지연 로딩의 모든 이점을
잃어 버리

EAGER를 사용하는 것은 전문적인 솔루션이 아닙니다.
Rafael

9

가장 좋은 해결책 중 하나는 application.properties 파일에 다음을 추가하는 것입니다. spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true


1
OP에게 부작용, 성능에 미치는 영향을 정확히 알려줄 수 있습니까?
PeS

3
지연로드의 뒷면에서 연결이 느리게로드 될 때마다 새 세션이 분기되므로 더 많은 연결이 분기되고 연결 풀에 약간의 압력이 발생합니다. 연결 수에 제한이있는 경우이 특성이 사용하기에 올바르지 않을 수 있습니다.
sreekmatta

2
일부의 경우 반 패턴 vladmihalcea.com/…
Uri Loya

7

선언 @PersistenceContext하면 EXTENDED이 문제도 해결 된다는 것을 알았습니다 .

@PersistenceContext(type = PersistenceContextType.EXTENDED)

1
안녕, 그런 변화에주의하십시오. TRANSACTION 범위 지속성 컨텍스트 작성이 지연되어 OP 의도였습니다. 따라서 문제는 무국적자가되고 싶은지 아닌지입니다. 이 설정은 시스템의 목적에 따라 다르며 너무 열심히 변경해서는 안됩니다. 무슨 말인지 알면 여기를 읽으십시오 stackoverflow.com/questions/2547817/…
kiedysktos

위험한. 이것은 정답이 아닙니다. 훨씬 더 정확하고 안전한 것 위에 다른 것들이 있습니다.
Rafael

5

내가 최근에 직면 한 문제로 내가 사용하여 해결했다.

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

더 자세한 설명 과 여기가 내 하루를 구했습니다.


5

목록이 느리게로드되어 목록이로드되지 않았습니다. 목록에 전화하는 것만으로는 충분하지 않습니다. 목록을 초기화하기 위해 Hibernate.initialize에서 사용하십시오. dosnt 작업이 list 요소에서 실행되고 각각에 대해 Hibernate.initialize를 호출하십시오. 이것은 트랜잭션 범위에서 돌아 오기 전에 이루어져야합니다. 볼 게시 할 수 있습니다.
검색-

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 

4

내 경우의 문제를 해결하기 위해이 줄이 누락되었습니다.

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

애플리케이션 컨텍스트 파일에서.

@Transactional메소드에 대한 주석은 고려되지 않았습니다.

대답이 누군가를 도울 수 있기를 바랍니다.


4

컨트롤러의 @Transactional 주석이 누락되었습니다

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

17
트랜잭션 관리는 비즈니스 로직이 상주하는 서비스 계층에 속한다고 주장합니다.
Sõber

트랜잭션 주석이 없습니다. 컨트롤러에는 이러한 주석이 없어야합니다. 이러한 주석은 서비스 수준에 있어야합니다.
Rafael

4

최대 절전 모드 @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()당신이 명시 적으로 요청했기 때문에 호출 은 다른 쿼리를 수행하여 판매를 가져옵니다.


4

당신이해야 할 두 가지 fetch = FetchType.LAZY.

@Transactional

Hibernate.initialize(topicById.getComments());

2

작업 사람들을 위해 기준 , 내가 발견

criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);

내가 필요한 모든 일을 했어

컬렉션의 초기 페치 모드는 성능을 제공하기 위해 FetchMode.LAZY로 설정되어 있지만 데이터가 필요할 때 해당 라인을 추가하고 완전히 채워진 객체를 즐기십시오.


2

제 경우에는 다음 코드가 문제였습니다.

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

데이터베이스에서 분리되어 최대 절전 모드가 더 이상 필요했을 때 필드에서 목록을 검색하지 않기 때문입니다. 분리하기 전에 초기화합니다.

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm

1

그 이유는 서비스 내부의 세션을 닫은 후에 컨트롤러에서 commentList를 가져 오려고하기 때문입니다.

topicById.getComments();

위는 최대 절전 모드 세션이 활성화 된 경우에만 commentList를로드합니다. 서비스에서 닫은 것 같습니다.

따라서 세션을 닫기 전에 commentList를 가져와야합니다.


2
그렇습니다, 이것은 문제 진술입니다. 또한Answer
Sarz

1

comments모델 클래스 의 컬렉션 Topic은 느리게로드되며, fetch = FetchType.EAGER특별히 주석을 달지 않으면 기본 동작 입니다.

대부분의 findTopicByID서비스가 Stateless Hibernate 세션을 사용하고 있을 가능성이 높습니다 . 상태 비 저장 세션 에는 첫 번째 수준 캐시가 없습니다. 즉, 지속성 컨텍스트가 없습니다. 나중에 반복하려고 할 때 commentsHibernate는 예외를 던질 것이다.

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

해결책은 다음과 같습니다.

  1. 주석 commentsfetch = FetchType.EAGER

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)   
    private Collection<Comment> comments = new LinkedHashSet<Comment>();
  2. 여전히 주석을 느리게로드하려면 Hibernate의 상태 저장 세션을 사용 하여 나중에 필요할 때 주석을 가져올 수 있습니다.


1

내 경우, 나는 / W 맵핑 B를 가지고 AB같은

A 있다

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

DAO층은 방법은 주석이 될 필요가 @Transactional당신과 매핑 주석하지 않은 경우 가져 오기 유형 - 열망


1

최선의 해결책은 아니지만 LazyInitializationException특히이 문제에 직면 한 사람들에게 Serialization도움이 될 것입니다. 여기에서는 느리게 초기화 된 속성과 null그 설정 을 확인합니다. 이를 위해 아래 클래스를 만듭니다.

public class RepositoryUtil {
    public static final boolean isCollectionInitialized(Collection<?> collection) {
        if (collection instanceof PersistentCollection)
            return ((PersistentCollection) collection).wasInitialized();
        else 
            return true;
    }   
}

느리게 초기화 된 속성이있는 Entity 클래스 내부에 아래와 같은 메소드를 추가하십시오. 이 메소드 안에 지연로드 특성을 모두 추가하십시오.

public void checkLazyIntialzation() {
    if (!RepositoryUtil.isCollectionInitialized(yourlazyproperty)) {
        yourlazyproperty= null;
    }

checkLazyIntialzation()데이터를로드하는 모든 장소 에서이 메소드를 호출하십시오 .

 YourEntity obj= entityManager.find(YourEntity.class,1L);
  obj.checkLazyIntialzation();

0

안녕하세요 모든 게시물이 늦게 도움이되기를 바랍니다.이 게시물에 대해 @GMK에 미리 감사드립니다. Hibernate.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'에 액세스 할 수 있습니다.


0

또 다른 방법으로 TransactionTemplate 을 사용 하여 지연 가져 오기를 감쌀 수 있습니다 . 처럼

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());

0

데이터베이스에 대한 "연결"이 닫힐 때 코드가 지연 JPA 관계에 액세스하기 때문에 문제점이 발생합니다 ( 지속성 컨텍스트 는 최대 절전 / JPA 측면에서 올바른 이름 임).

Spring Boot에서이를 해결하는 간단한 방법은 서비스 계층을 정의하고 @Transactional주석을 사용하는 것 입니다. 메소드의이 주석은 저장소 계층으로 전파되고 메소드가 완료 될 때까지 지속성 컨텍스트를 유지하는 트랜잭션을 작성합니다. 트랜잭션 메소드 내부의 콜렉션에 액세스하면 Hibernate / JPA는 데이터베이스에서 데이터를 가져옵니다.

귀하의 경우에는, 당신은 단지와 주석을 필요로 @Transactional하는 방법 findTopicByID(id)당신의 TopicService과 (예를 들어, 크기를 요청하여) 그 방법으로 컬렉션의 페치 강제 :

    @Transactional(readOnly = true)
    public Topic findTopicById(Long id) {
        Topic topic = TopicRepository.findById(id).orElse(null);
        topic.getComments().size();
        return topic;
    }

0

지연 초기화 예외를 제거하려면 분리 된 오브젝트로 조작 할 때 지연 콜렉션을 호출하지 않아야합니다.

내 의견으로는 최선의 접근 방식은 엔티티가 아닌 DTO를 사용하는 것입니다. 이 경우 사용하려는 필드를 명시 적으로 설정할 수 있습니다. 평소처럼 충분합니다. jackson과 같은 ObjectMapper또는 hashCodeLombok에 의해 생성 된 것이 메소드를 암시 적으로 호출 한다는 것을 걱정할 필요가 없습니다 .

특정한 경우에는 @EntityGrpaph주석 을 사용 하여 엔터티에 eager있는 경우에도로드 할 수 있습니다 fetchType=lazy.


0

이 지연 초기화 문제에 대한 여러 가지 해결책이 있습니다.

1) 연관 페치 유형을 LAZY에서 EAGER로 변경하십시오. 그러나 이는 성능을 저하 시키므로 권장되지 않습니다.

2) 연결된 객체에서 FetchType.LAZY를 사용하고 서비스 계층 메서드에서 트랜잭션 주석을 사용하여 세션이 열려 있고 topicById.getComments ()를 호출하면 자식 객체 (comments)가로드됩니다.

3) 또한 컨트롤러 계층에서 엔티티 대신 DTO 객체를 사용하십시오. 귀하의 경우 세션은 컨트롤러 계층에서 닫힙니다. 서비스 계층에서 엔티티를 DTO로 변환하는 것이 좋습니다.


-11

Set 대신 List를 사용하여 해결했습니다.

private List<Categories> children = new ArrayList<Categories>();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.