작성
·
194
·
수정됨
-1
배운것을 바탕으로 개인적으로 게시판을 만들어보는 중입니다. 게시물을 추가할 때 다음과 같은 에러가 발생해서 몇시간째 애를 먹고있는 중입니다.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.myproject.jpaboard.domain.Member.posts: could not initialize proxy - no Session
아무래도 Post(게시물) 엔티티의 연관관계 편의 메서드에서 문제가 발생하는 것 같습니다. 서비스 계층에 @Transactional도 붙여줬음에도 계속해서 문제가 발생해서 질문 남깁니다. 유일한 해결책은 Member의 posts에 EAGER을 붙이는 방법이었습니다. 하지만 이는 적절치 않아보입니다. 어떻게 해야 해결할 수 있을까요.
핵심이 되는 코드들을 아래에 추가했습니다.
package com.myproject.jpaboard.web.controller;
import com.myproject.jpaboard.domain.Member;
import com.myproject.jpaboard.domain.Post;
import com.myproject.jpaboard.web.SessionConst;
import com.myproject.jpaboard.web.form.PostForm;
import com.myproject.jpaboard.web.repository.BoardRepository;
import com.myproject.jpaboard.web.service.BoardService;
import com.myproject.jpaboard.web.service.PostService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/post")
@RequiredArgsConstructor
@Slf4j
public class PostController {
private final BoardService boardService;
private final BoardRepository boardRepository;
private final PostService postService;
/**
* 게시물 추가
*/
@PostMapping("/new")
public String addPost(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, @Validated PostForm postForm, BindingResult bindingResult) {
log.info("postForm={}", postForm);
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "newPost";
}
postService.addPost(postForm, loginMember);
return "redirect:/board/list";
}
}
// Post.java
@Entity
@Getter @Setter
public class Post {
@Id
@GeneratedValue
@Column(name = "post_id")
private Long id;
private String title;
private String writer;
@Lob
@Column(columnDefinition="LONGTEXT")
private String content;
@Column(updatable = false)
private LocalDateTime createdTime;
private LocalDateTime lastModifiedTime;
private Long viewCount;
@ManyToOne(fetch = FetchType.LAZY) // 다쪽이 연관관계의 주인
@JoinColumn(name = "member_id")
private Member member;
@Enumerated(EnumType.STRING)
private CategoryType category;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
public Post() {}
// 연관관계 편의 메서드
public void setMember(Member member) {
this.member = member;
member.getPosts().add(this);
}
@Override
public String toString() {
return "Post{" +
"id=" + id +
", title='" + title + '\'' +
", writer='" + writer + '\'' +
", content='" + content + '\'' +
", createdTime=" + createdTime +
", lastModifiedTime=" + lastModifiedTime +
", viewCount=" + viewCount +
", category=" + category +
'}';
}
}
// Member.java
@Entity
@Getter @Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String email;
private String password;
private String name;
@Embedded
private Address address;
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<Post> posts = new ArrayList<>();
/**
* POST 추가 로직 (도메인 모델 패턴)
*/
// public void addPost(Post post) {
//
//
// }
@Override
public String toString() {
return "Member{" +
"address=" + address +
", name='" + name + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", id=" + id +
'}';
}
}
// PostService.java
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PostService {
private final BoardRepository boardRepository;
private final PostRepository postRepository;
/**
* 게시물 추가
*/
@Transactional
public void addPost(PostForm postForm, Member loginMember) {
Post post = new Post();
postForm.setCreatedTime(LocalDateTime.now());
// setter로 세팅
post.setTitle(postForm.getTitle());
post.setWriter(postForm.getWriter());
post.setContent(postForm.getContent());
post.setCreatedTime(postForm.getCreatedTime());
post.setCategory(postForm.getCategory());
post.setViewCount(0L);
post.setWriter(loginMember.getName());
post.setMember(loginMember);
postRepository.save(post);
}
}
답변 2
0
안녕하세요, 인프런 AI 인턴입니다. Jaesang Yoon님의 문제에 대하여 관련된 내용을 찾았습니다.
LazyInitializationException은 Hibernate 세션이 이미 종료된 이후에 지연 로딩을 하려고 할 때 자주 발생하는 오류입니다. 즉, 엔티티를 로딩한 세션의 생명주기가 끝나고 난 뒤에 연관된 엔티티를 불러오려 할 때 나타납니다.
Jaesang Yoon님의 경우, Member
엔티티 내부에 있는 posts
컬렉션에 접근하려 할 때 해당 오류가 발생한 것으로 보입니다. 오류 메시지에서 “could not initialize proxy - no Session”이라는 부분이 바로 그 핵심입니다.
이 문제를 해결하기 위한 일반적인 방법은 두 가지가 있습니다:
1. @Transactional 어노테이션 사용: Jaesang Yoon님께서는 이미 서비스 계층에서 사용하고 계신 것으로 보입니다. 그러나 이 오류가 계속 발생한다면, 해당 데이터에 접근하는 로직이 모두 @Transactional 어노테이션으로 묶여있는지 확인해보세요. 특히, Member
의 posts
컬렉션에 접근하는 과정이 해당 어노테이션 내에서 이루어져야 합니다.
Member
를 조회할 때, posts
도 함께 조회하도록 쿼리를 작성할 수 있습니다.관련하여 링크를 첨부해 드립니다:
- failed to lazily initialize a collection of role 오류 관련 문의
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
지식공유자님의 답변을 기다립니다.