인프런 커뮤니티 질문&답변

조진수님의 프로필 이미지
조진수

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

즉시 로딩과 지연 로딩

failed to lazily initialize a collection of role 에러 질문

작성

·

457

1

강의를 들으면서 혼자 프로젝트를 진행중에 질문드립니다.

Member 와 Post 가 1:N 양방향 관계에 있고 지연로딩으로 설정하였습니다. 아래는 postService 클래스의 post를 저장하는 메소드 입니다.

public class PostService {
private final PostRepository postRepository;

@Transactional
public Long createPost(Post post){
log.info("new post = "+post);
postRepository.save(post);
Post byId = postRepository.findById(post.getId()).get();
log.info("Member = " + byId.getMember());
log.info("MemberPosts = " + byId.getMember().getPosts());
return post.getId();
}

일단 post가 제대로 저장이 됩니다. 근데 위 코드의 log.info("memberPosts = " + byId.getMember.getPost()) 에서 failed to lazily initialize a collection of role 에러가 발생합니다. 해당 오류가 영속성 컨텍스트가 종료되어 지연로딩이 불가능 해서 나온 오류라고 하셨는데, createPost 메서드에 @Transactional 에노테이션을 붙혀놨는데도 영속성 컨텍스트가 종료되나요?

오류가 나는 로그 위의 byId.getMember() 의 로그는 정상출력이 되는데 여기서 member는 영속성 컨텍스트가 살아있어서 getMember.getPost()와는  다른 결과가 나온 것인가요?

 

해당 코드를 실행했을 때 로그입니다.

2022-05-30 23:32:58.015  INFO 35864 --- [nio-8080-exec-1] com.mytube.service.PostService           : new post = Post(title=dwq, member=Member(id=1, userId=a, password=a, userEmail=a))

2022-05-30 23:32:58.016 DEBUG 35864 --- [nio-8080-exec-1] org.hibernate.SQL                        : 

    call next value for hibernate_sequence

2022-05-30 23:32:58.017  INFO 35864 --- [nio-8080-exec-1] com.mytube.service.PostService           : Member = Member(id=1, userId=a, password=a, userEmail=a)

2022-05-30 23:32:58.017  INFO 35864 --- [nio-8080-exec-1] c.mytube.web.interceptor.LogInterceptor  : RESPONSE [e95af4ef-3220-4391-bbae-7e6fb049c9d0][/posts/new]

2022-05-30 23:32:58.018 ERROR 35864 --- [nio-8080-exec-1] c.mytube.web.interceptor.LogInterceptor  : afterCompletion error!!

 

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mytube.domain.Member.posts, could not initialize proxy - no Session

 

그리고 문제가 되는 getMember.getPosts() 로그를 주석처리했을 때 로그입니다.

2022-05-30 23:35:19.862  INFO 39788 --- [nio-8080-exec-8] com.mytube.service.PostService           : new post = Post(title=asd, member=Member(id=1, userId=a, password=a, userEmail=a))

2022-05-30 23:35:19.869 DEBUG 39788 --- [nio-8080-exec-8] org.hibernate.SQL                        : 

    call next value for hibernate_sequence

2022-05-30 23:35:19.873  INFO 39788 --- [nio-8080-exec-8] com.mytube.service.PostService           : Member = Member(id=1, userId=a, password=a, userEmail=a)

2022-05-30 23:35:19.876 DEBUG 39788 --- [nio-8080-exec-8] org.hibernate.SQL                        : 

    insert 

    into

        posts

        (created_date, last_modified_date, created_by, last_modified_by, content, member_id, title, post_id) 

    values

        (?, ?, ?, ?, ?, ?, ?, ?)

 

로그를 보니 post가 영속상태에 있어서 따로 select 쿼리가 나가지 않아도

 Post byId postRepository.findById(post.getId()).get();

의 결과를 영속성 컨텍스트에서 가져오고 post의 member 또한 post가 영속상태에서 프록시 member가 아닌 실제 member를 가진것같습니다.

근데 member.getPost()는 왜 영속상태가 끝났다는 걸까요??

 

답변 3

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 조진수님

엔티티를 세션에 보관하면 안됩니다. 세션에는 DTO를 보관해주세요.

지금 세션에 member 엔티티를 보관하고, 또 해당 엔티티를 엮어서 그대로 Post와 함께 persist하기 때문에 post를 다시 조회할 때 세션에 보관된 member가 조회되는 현상이 발생합니다. 이 member는 프록시 기능을 상실한 상태이기 때문에 이런 문제가 발생합니다.

감사합니다.

0

조진수님의 프로필 이미지
조진수
질문자

https://drive.google.com/file/d/17ZWGBPZ-WEz-XitsVn6qRvDIiisRuApS/view?usp=sharing

 

h2 데이터베이스를 키고 스프링부트 어플리케이션을 실행하고 localhost:8080 에서 로그인 후 글 게시판에 새글 작성을 하면 해당 오류가 나옵니다. 감사합니다

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 조진수님

전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 실행 방법을 알려주세요.

2. 어떻게 문제를 확인할 수 있는지 자세한 설명을 남겨주세요.

감사합니다.

 

조진수님의 프로필 이미지
조진수

작성한 질문수

질문하기