복붙노트

[SPRING] Spring JSP 페이지에서 콜렉션을 사용하는 동안 Hibernate LazyInitializationException이 발생한다.

SPRING

Spring JSP 페이지에서 콜렉션을 사용하는 동안 Hibernate LazyInitializationException이 발생한다.

나는 이런 엔티티가있다 :

@Entity
@Table(name = "ASSESSMENT")
public class Assessment {

    //All other fields..

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "assessment")
    @OrderBy(value = "order ASC")
    private List<AssessmentPart> assessmentParts = new LinkedList<>();

    public List<AssessmentPart> getAssessmentParts() {
        return assessmentParts;
    }

    //All other getters/setters
}

다른 하나 :

@Entity
@Table(name = "ASSESSMENT_PART")
public class AssessmentPart {

    //All other fields

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "ASSESSMENT_ID", nullable = false)
    private Assessment assessment;

    public Assessment getAssessment() {
        return assessment;
    }

    public void setAssessment(Assessment assessment) {
        this.assessment = assessment;
    }

    //All other getters/setters
}

평가 파트는 평가 엔티티에서 지연로드됩니다. 나는 또한 Spring Controller 메소드를 Transactional하고 데이터베이스로부터 평가 부분을로드한다.

@Transactional
public void doSomething(String partId, Map<String, Object> model) {

    AssessmentPart assessmentPart = //laods a part with entity manager
    Assessment assessment = assessmentPart.getAssessment(); //Getting the assessments

    model.put("assessmentParts", assessment.getAssessmentParts()); //adding all assessments parts into spring model map
}

스프링 모델 맵에 평가 파트를 추가하면 JSP 페이지에서 사용할 수있게되고 JSTL을 사용하여 루프를 반복합니다.

<c:forEach var="assessmentPart" items="${assessmentParts}">
     //Not loading any lazy stuff, just getting an ID of assessment part
</c:forEach>

이 JSP 페이지에서 예외가 발생합니다.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: my.package.something.Assessment.assessmentParts, could not initialize proxy - no Session

이 컬렉션이 이미 트랜잭션에로드 된 경우 어떻게 가능합니까? 난 그냥 루프를 통해 노력하고있어, 최대 절전 모드는 이미로드 되었기 때문에이 시점에서 아무것도로드하지 않아야합니다. 이 이상한 일이 왜 일어나는거야?

해결법

  1. ==============================

    1.보기에서 entitymanager는 이미 닫혀 있으므로 컬렉션의 요소가 속성을 검색하지 못합니다. 컨트롤러에 작성한 코드는 컬렉션의 요소를 초기화하지 않지만 (LAZY 컬렉션) 콜렉션 만 초기화됩니다 (내부 요소는 초기화하지 않습니다).

    보기에서 entitymanager는 이미 닫혀 있으므로 컬렉션의 요소가 속성을 검색하지 못합니다. 컨트롤러에 작성한 코드는 컬렉션의 요소를 초기화하지 않지만 (LAZY 컬렉션) 콜렉션 만 초기화됩니다 (내부 요소는 초기화하지 않습니다).

    웹 구성에서 OpenEntityManagerInViewFilter를 구성하여 entitymanager를 열린 상태로 유지하십시오.

    또는 컨트롤러 코드를 변경하여 Hibernate.initialize를 호출하여 콜렉션을 올바르게 초기화하십시오.

    @Transactional
    public void doSomething(String partId, Map<String, Object> model) {
    
        AssessmentPart assessmentPart = //laods a part with entity manager
        Assessment assessment = assessmentPart.getAssessment(); //Getting the assessments
        Hibernate.initialize(assesment.getAssesmentParts()); // Init collection
        model.put("assessmentParts", assessment.getAssessmentParts()); //adding all assessments parts into spring model map
    }
    

    그 중 하나 또는 컬렉션의 열심히 가져 오는 강제로 사용자 지정 쿼리를 만듭니다.

  2. ==============================

    2.변화

    변화

    model.put("assessmentParts", assessment.getAssessmentParts());
    

    Hibernate.initialize(assessment.getAssessmentParts());
    

    컬렉션을 초기화합니다.

    메소드 호출 assessment.getAssessmentParts ()가 콜렉션을 초기화하지 않습니다. 이 메소드 호출은 콜렉션 래퍼와 Hibernate.initialize 메소드로 수동 초기화를 위해 전달해야하는 래퍼를 반환 할 것이다.

    편집하다:

    JPA를 사용하면 JPQL 가져 오기 조인을 사용하여 평가와 함께 AssessmentParts를 가져 와서 기본 동작을 재정의 할 수 있습니다.

    SELECT a FROM Assessment asmt LEFT JOIN FETCH asmt.assessmentParts WHERE asmt.id = :id
    
  3. ==============================

    3.EntityManager에서 AssessmentPart를로드하면로드 평가가됩니다 @ManyToOne (fetch = FetchType.EAGER)

    EntityManager에서 AssessmentPart를로드하면로드 평가가됩니다 @ManyToOne (fetch = FetchType.EAGER)

    AssessmentPart assessmentPart = //laods a part with entity manager
    Assessment assessment = assessmentPart.getAssessment();
    

    @OneToMany (fetch = FetchType.LAZY)가 아니므로 평가에서 AssessmentParts를 추출하려고 시도했지만 세션이 이미 닫혀 있습니다.

    model.put("assessmentParts", assessment.getAssessmentParts());
    

    새로운 방법으로 EntityManager에서 Assessment by AssessmentParts 목록을 얻으면 문제가 해결됩니다.

  4. from https://stackoverflow.com/questions/19047835/hibernate-lazyinitializationexception-while-using-collection-in-spring-jsp-page by cc-by-sa and MIT license