IT이야기

"역할 컬렉션을 느릿느릿 초기화하지 못했습니다" 최대 절전 모드 예외 해결 방법

cyworld 2022. 6. 18. 09:37
반응형

"역할 컬렉션을 느릿느릿 초기화하지 못했습니다" 최대 절전 모드 예외 해결 방법

문제가 있습니다.

org.internate 를 선택합니다.Laze Initialization(레이지 초기화)예외: 역할: 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:forEqual loop이 있는

것을 CommentTopic 필드 .comments 삭제:

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

수집은 기본적으로 느리게 로드됩니다. 자세한 내용은 이 항목을 참조하십시오.

내 경험상, 나는 유명한 게으름을 해결하기 위해 다음과 같은 방법을 가지고 있다.초기화예외:

(1) Hibernate를 사용한다.초기화하다

Hibernate.initialize(topics.getComments());

(2) JOIN FETCH 사용

JPQL에서 JOIN FETCH 구문을 사용하여 하위 컬렉션을 명시적으로 가져올 수 있습니다.이것은 마치 열심(EGER)의 페치(Fetching)와 같은 것이다.

(3) Open Session 사용InViewFilter(InViewFilter)

Laze Initialization(레이지 초기화)뷰 레이어에서 예외가 발생하는 경우가 많습니다.Spring 프레임워크를 사용하는 경우 OpenSession을 사용할 수 있습니다.InViewFilter 입니다.하지만 그렇게 하는 것은 권장하지 않습니다.올바르게 사용하지 않으면 성능 문제가 발생할 수 있습니다.

오래된 질문인 건 알지만 돕고 싶어요.필요한 서비스 메서드에 트랜잭션 주석을 추가할 수 있습니다.이 경우 findTopicByID(ID)는 다음을 가져야 합니다.

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

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

기타 솔루션에 대해서:

fetch = FetchType.EAGER 

는 좋은 방법이 아닙니다.필요한 경우에만 사용해야 합니다.

Hibernate.initialize(topics.getComments());

휴지 상태의 이니셜라이저는 클래스를 휴지 상태의 테크놀로지에 바인드 합니다.만약 당신이 유연해지는 것을 목표로 한다면 좋은 방법이 아니다.

도움이 되었으면 좋겠다

문제의 원인:

로는 hibernate는 은, 「hibernate」(동면)를 합니다.★★★★★★★★★★★★★★★★★★★★★★★,collection의 암호(여기서 신신여여여여여여여여여여여여여)로commentsTopicclass)는, 휴지 상태가 데이타베이스로부터 취득합니다만, 문제는 컨트롤러(JPA 세션이 닫혀 있는 경우)로 수집을 취득하고 있는 것입니다.서는 「」를 ).comments( 션 : 。

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

())에 "" getComments이 있습니다.JPA session종료되었습니다)로 인해 예외가 발생합니다., ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★comments다음과 같이 jsp 파일에 수집합니다(컨트롤러에 가져올 수 없습니다).

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

동일한 이유로 동일한 예외가 계속 발생할 수 있습니다.

문제 해결:

이 은 두 수 입니다.FetchType.Eager에서 (한 컬렉션로드하는 이 ()을 FetchType절히::::::

이 이 을 코드 스니펫을 코드 스니펫(snoption of code)에 .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 session 매뉴얼에 기재되어 와 같이 '사용하고 ."to allow for lazy loading in web views despite the original transactions already being completed."이렇게 하면 JPA 세션이 조금 더 오래 열리기 때문에 jsp 파일 및 컨트롤러 클래스에 수집을 쉽게 로드할 수 있습니다.

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

는 이 합니다.@Transactional할 수 것

를 처리하는 가장 좋은 방법은 다음과 같이 쿼리 시간에 가져오는 것입니다.

select t
from Topic t
left join fetch t.comments

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

때문에 이 때 꼭, 이 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때.FetchType.LAZY시의 「어소시에이션」으로됩니다.@Transactional를 사용한 스코프Hibernate.initialize제2의

이 문제는 휴지 상태 세션이 닫힌 상태에서 Atribute에 액세스하기 때문에 발생합니다.컨트롤러에 휴지 상태 트랜잭션이 없습니다.

가능한 해결책:

  1. 이 모든 로직은 컨트롤러가 아닌 (@Transactional을 사용하여) 서비스 레이어에서 수행합니다.이 작업을 수행할 수 있는 적절한 장소가 있어야 합니다. 컨트롤러(이 경우 모델을 로드하는 인터페이스)가 아니라 앱의 로직의 일부입니다.서비스 계층의 모든 작업은 트랜잭션 방식으로 진행되어야 합니다.이 행을 TopicService.findTopicBy로 이동합니다.ID 방식:

    컬렉션 commentList = topicById.getComments();

  2. 'lazy' 대신 'eager'를 사용하세요.지금 당신은 'lazy'를 사용하지 않고 있습니다.이 솔루션은 실제 솔루션이 아닙니다.게을러지를사용하는경우는일시적인(매우 일시적인) 회피책처럼 기능합니다.

  3. 컨트롤러에서 @Transactional을 사용합니다.여기서는 사용하지 마십시오.서비스 계층과 프레젠테이션이 혼재되어 있기 때문에 좋은 설계가 아닙니다.
  4. Open Session 사용InViewFilter, 많은 단점 보고, 불안정 가능성.

일반적으로 가장 좋은 해결책은 1입니다.

그 이유는 느린 부하를 사용하면 세션이 닫히기 때문입니다.

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

  1. 게으른 짐을 쓰지 마세요.

    ★★lazy=false 또는 XML로 설정합니다.@OneToMany(fetch = FetchType.EAGER)주석으로.

  2. 느린 부하를 사용하세요.

    ★★lazy=true 또는 XML로 설정합니다.@OneToMany(fetch = FetchType.LAZY)주석으로.

    OpenSessionInViewFilter filter 안에서web.xml

상세 POST를 참조해 주세요.

수집을 느리게 로드하려면 활성 세션이 있어야 합니다.웹 앱에서는 두 가지 방법이 있습니다.[ Open Session In View ]패턴을 사용하면 인터셉터를 사용하여 요청 시작 세션을 열고 마지막에 세션을 닫을 수 있습니다.확실한 예외 처리를 하지 않으면 모든 세션을 바인드하여 앱이 중단될 수 있습니다.

다른 방법은 컨트롤러에서 필요한 모든 데이터를 수집하고 세션을 닫은 다음 모델에 데이터를 넣는 것입니다.저는 개인적으로 이 방식이 MVC 패턴의 정신에 조금 더 가까운 것처럼 보이기 때문에 더 선호합니다.또한 이 방법으로 데이터베이스에서 오류가 발생한 경우 보기 렌더러에서 발생한 경우보다 훨씬 더 잘 처리할 수 있습니다.이 시나리오의 친구는 휴지 상태입니다.initialize(myTopic.getComments()).또한 요청마다 새 트랜잭션을 만들기 때문에 개체를 세션에 다시 연결해야 합니다.session.lock(myTopic, LockMode)을 사용합니다.NONE)을 참조해 주세요.

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

엔티티와 Java 오브젝트 컬렉션 또는 목록(예: Long type) 간의 관계를 설정하려고 할 경우 다음과 같이 됩니다.

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

가지 꼭 있어야 할 .fetch = FetchType.LAZY..

@Transactional

그리고.

Hibernate.initialize(topicById.getComments());

이 Lazy Initialization 문제에는 여러 가지 해결책이 있습니다.

1) 관련지어져 있는 Fetch 타입을 LAGY에서 OVER로 변경합니다만, 퍼포먼스가 저하되기 때문에 좋은 방법은 아닙니다.

2) Fetch Type을 사용합니다.연관된 오브젝트에 LAGY가 있으며 세션이 열린 상태로 유지되고 topicById.getComments()를 호출할 때 하위 오브젝트(댓글)가 로드되도록 서비스 계층 메서드에서 트랜잭션 주석을 사용합니다.

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

나는 선언 내가알게 된 건을 발견했다.@PersistenceContext~하듯이로EXTENDED또한 이 문제:는 이문제도 해결합니다를 해결한다.

@PersistenceContext(type = PersistenceContextType.EXTENDED)

내 경우 문제를 해결하기 위해 이 줄을 놓쳤다.

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

응용 프로그램 다운로드 파일에 있습니다.

그 그@Transactional메서드에 Annotation을 고려하지 않았다.방법에 대한 주석이고려되지 않았습니다.

그 대답이 누군가에게 도움이 되기를 바란다.

목록을 로드하는 데 시간이 걸려서 목록이 로드되지 않았습니다. 목록에 등록하기 위한 전화로는 충분하지 않습니다.를 휴지 상태로 사용합니다.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 

그것은 내가 최근에 직면했던 문제였고 나는 그것을 이용하여 해결했다.

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

여기에 더 자세한 설명이 있어서 다행이에요.

@컨트롤러에 트랜잭션 주석이 없습니다.

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

JWT 토큰을 생성하는 메서드를 두 번째로 실행한 후 이 오류가 발생하였습니다.

user.getUsersRole().stream().ForEachOrder(ur) -> roles.add(ur.getRoleId) ; 행이 오류를 생성했습니다.

// MyUserDetails.java

@Service
public class MyUserDetails implements UserDetailsService {

  @Override
  public UserDetails loadUserByUsername(String email) {

    /* ERROR
    /* org.hibernate.LazyInitializationException: failed to 
    /* lazily initialize a collection of role: 
    /* com.organizator.backend.model.User.usersRole, 
    /* could not initialize proxy - no Session */
    user.getUsersRole().stream().forEachOrdered((ur) ->
           roles.add(ur.getRoleId()));

에는 ★★★★★★★★★★★★★★★★★★★★★★★★★.@Transacctional되었다.

// MyUserDetails.java

import org.springframework.transaction.annotation.Transactional;

@Service
public class MyUserDetails implements UserDetailsService {

  @Override
  @Transactional // <-- added
  public UserDetails loadUserByUsername(String email) {

    /* No Error */
    user.getUsersRole().stream().forEachOrdered((ur) ->
           roles.add(ur.getRoleId()));

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

에서는 "", "", "", "", "", ""를 호출한 사실이 됩니다.ticket.getSales()다른 쿼리를 실행하여 판매를 가져옵니다.명시적으로 요청했기 때문입니다.

이 문제는 데이터베이스에 대한 "접속"이 닫혀 있을 때 코드가 느린 JPA 관계에 액세스하기 때문에 발생합니다(영속 컨텍스트는 휴지 상태/J의 관점에서 올바른 이름입니다).PA)

하는 간단한 하고 Spring Boot를 하는 입니다.@Transactional 가 완료될 둡니다.메서드의 이 주석은 리포지토리 계층으로 전파되는 트랜잭션을 생성하고 메서드가 완료될 때까지 지속성 컨텍스트를 열어 둡니다.인 Hibernate/JJ컬렉션 Hibernate/.PA pa pa pa pa pa pa pa pa pa pa pa pa pa pa pa pa pa pa

같은 에는 그냥 에 '아까', '아까', '아까', '아까', '아까', 이렇게 하면 .@TransactionalfindTopicByID(id) 안에서TopicService(를 들어 등) 이 (를 들어, 컬렉션 를 물어봅니다.

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

느린 초기화 예외를 없애려면 분리된 개체로 작업할 때 느린 수집을 요청하지 마십시오.

내 생각에 최선의 접근법은 엔티티가 아닌 DTO를 사용하는 것이다.이 경우 사용할 필드를 명시적으로 설정할 수 있습니다.을 사용하다ObjectMapper , 「」hashCode롬복의

정, 을, 을, 을, 을, 을, 을, 습, 습, 습, 습, 습, 습, for, for, for 등을 사용할 수 있습니다.@EntityGrpaph "주석"을 만들 수 .eager 있어도 fetchType=lazy를 참조해 주세요.

이것은 오래된 질문이지만, 아래의 정보는 이에 대한 답을 찾는 사람들에게 도움이 될 수 있습니다.

@VladMihalcea 。는 안 된다FetchType.EAGERTopic엔티티(필요한 경우)를 지정합니다.

하지 않고, 「」를 할 수 는,join fetch를 사용하여, 을 사용합니다.@NamedEntityGraph ★★★★★★★★★★★★★★★★★」@EntityGraph 재지정할 수 있습니다.FetchType.LAZY )@OneToMany어소시에이션은 디폴트로 LAGY)를 사용해, 실행시에 코멘트를 로드합니다.Topic 필요한 경우에만.즉, 코멘트를 실제로 필요한 메서드(쿼리)로만 로드하는 것을 제한합니다.엔티티 그래프(JPA)는 다음을 정의합니다.

엔티티 그래프는 find 메서드와 함께 사용하거나 FetchType 시멘틱을 재정의하거나 증강하기 위한 쿼리 힌트로 사용할 수 있습니다.

여기서 JPA의 를 참고하여 사용할 수 있습니다.또는 스프링 데이터 JPA를 사용하는 경우 스프링에서 제공하는 예를 기반으로 사용할 수 있습니다.

Criteria를 사용하는 사람은

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

내가 필요한 건 다 했어

수집의 초기 가져오기 모드가 FetchMode로 설정됩니다.퍼포먼스 제공은 귀찮지만 데이터가 필요할 때는 그 행을 추가하여 완전히 채워진 오브젝트를 즐길 수 있습니다.

제 경우 다음 코드가 문제가 되었습니다.

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

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

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

좋은 해결책은 , 마주보고 있는 에게는, 가장 좋은 해결책입니다.LazyInitializationException 특특 es es es es에Serialization이게 도움이 될 거야여기서 느긋하게 초기화된 속성과 설정을 확인합니다.null그런 분들에게.이를 위해 아래 클래스를 만듭니다.

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

느긋하게 초기화된 속성을 가진 엔티티 클래스에 다음과 같은 메서드를 추가합니다.이 메서드에 로딩이 느긋한 속성을 모두 추가합니다.

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

이것을 호출하다checkLazyIntialzation()데이터를 로드하는 모든 위치에서 메서드를 사용합니다.

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

그 이유는 서비스 내에서 세션을 종료한 후 컨트롤러에서 commentList를 취득하려고 하기 때문입니다.

topicById.getComments();

위는 휴지 상태 세션이 활성화되어 있는 경우에만 comment List를 로드합니다.이 세션은 서비스에서 닫혔을 것입니다.

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

'''comments 클래스 ★★★★★★★★★★★★★★★★★★★★★★★★」Topic로딩되어 있습니다.은, 에 붙이지 입니다.이것은, 에 주석을 달지 않는 경우의 디폴트 동작입니다.fetch = FetchType.EAGER체적적구

대부분의 경우, 당신의findTopicByID서비스가 스테이트리스 휴지 상태 세션을 사용하고 있습니다.스테이트리스 세션에는 첫 번째 수준의 캐시가 없습니다.즉, 영속 컨텍스트가 없습니다.나중에 당신이 반복하려고 할 때comments 가 되면 예외가

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의 스테이트풀 세션을 사용하여 나중에 필요에 따라 코멘트를 가져올 수 있습니다.

.A ★★★★★★★★★★★★★★★★★」B

A 있다

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

DAO레이어, 메서드에 주석을 붙여야 합니다.@Transactional매핑에 Fetch Type - Eager로 주석을 달지 않은 경우

안녕하세요, 모두 늦게나마 다른 사람에게 도움이 되기를 희망하며, 이 휴지 상태 포스트에 대해 @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'에 액세스할 수 있습니다.

언급URL : https://stackoverflow.com/questions/11746499/how-to-solve-the-failed-to-lazily-initialize-a-collection-of-role-hibernate-ex

반응형