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

건후레이크님의 프로필 이미지
건후레이크

작성한 질문수

스프링 데이터 JPA

org.hibernate.LazyInitializationException( could not initialize proxy ) 에러 질문합니다!

작성

·

4.7K

0

안녕하세요.

게시글을 등록하는 기능을 구현중인데, LazyInitializationException 에러를 해결 못하고 있습니다.

테이블 관계(Account - Post) 는 양방향 관계로 설정하였고, 다음과 같이 설정했습니다.

Account 테이블

@Entity
@Getter
@Setter
public class Account implements UserDetails {
@Id
@GeneratedValue
private Integer accountNo;

// 다른 컬럼들 생략...

@OneToMany(mappedBy = "account")
private List<Post> post = new ArrayList<>();

Post 테이블

@Entity
@Getter
@Setter
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer postNo;

@ManyToOne
@JoinColumn(name = "accountNo")
private Account account;

//다른 컬름들 생략...

public void setAccount(Account account) {
if(this.account != null){
this.account.getPost().remove(this);
}
this.account = account;
this.account.getPost().add(this);
}

문제가 발생한 로직 함수 부분

@PostMapping("")
public ResponseEntity enrollPost(@RequestParam("file") MultipartFile multipartFile,
@RequestParam("content") String content,
@RequestParam("score") float score,
@AuthenticationPrincipal Account account) throws Exception{

Path fileNameAndPath = Paths.get("./images/",multipartFile.getOriginalFilename());

try{
Files.write(fileNameAndPath, multipartFile.getBytes());
}catch (IOException e){
throw new InvalidImageException("이미지 업로드에 실패했습니다.");
}

Post post = new Post();
post.setScore(score);
post.setContent(content);
post.setPostPic(fileNameAndPath.toString());
post.setAccount(account); << 문제가 발생한 부분!! #############

Post save = postRepository.save(post);

 위와 같습니다.

문제가 발생한 부분은 아래 함수를 처리하다가 오류가 생겼습니다.

위의 post.setAccount(account) 부분에서 

public void setAccount(Account account) {
if(this.account != null){
this.account.getPost().remove(this);
}
this.account = account;
this.account.getPost().add(this); << 문제가 발생한 지점!! ##############
}

account.getPost()를 가져오는 부분에서 Lazy초기화에러가 발생했습니다.

해당 문제는 Account의 post @OneToMany 컬럼에 fetch = FetchType.EAGER 설정을 주면 쉽게 해결이 되는데,

Post의 FetchType을 Eager로 주게 될 경우, 유저를 조회할 때마다 항상 Post를 조회하는게 성능상 문제가 될것같아서 위와 같은 방식은 사용하고 싶지 않습니다.

@PostMapping 함수 로직을 실행하기전에 

@AuthenticationPrincipal Account account

인증권한 확인하는부분에서 Accont의 데이터를 한번 조회해오는데, 로그는 다음과 같습니다.

/* select
generatedAlias0
from
Account as generatedAlias0
where
generatedAlias0.email=:param0 */ select
account0_.accountNo as accountN1_0_,
account0_.accountId as accountI2_0_,
account0_.accountName as accountN3_0_,
account0_.accountPwd as accountP4_0_,
account0_.authority as authorit5_0_,
account0_.bio as bio6_0_,
account0_.email as email7_0_,
account0_.instagram as instagra8_0_,
account0_.profilePic as profileP9_0_,
account0_.regDate as regDate10_0_,
account0_.twitter as twitter11_0_,
account0_.updDate as updDate12_0_,
account0_.useStateCode as useStat13_0_
from
Account account0_
where
account0_.email=?

Account 테이블에서 Post를 참조하고 있는 리스트를 가지고 오지 않아서 에러가 발생하는것 같은데, 어떻게 하면 Account가 참조하고 있는 Post정보를 가지고올 수 있을까요?

에러가 발생한 로그는 아래와 같습니다. 

//  2020-01-20 22:04:40.867 ERROR 6330 --- [nio-8098-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.toffeestory.backend.account.Account.post, could not initialize proxy - no Session] with root cause
//
// org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.toffeestory.backend.account.Account.post, could not initialize proxy - no Session
// at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602) ~[hibernate-core-5.3.11.Final.jar:5.3.11.Final]
// at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217) ~[hibernate-core-5.3.11.Final.jar:5.3.11.Final]
// at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:581) ~[hibernate-core-5.3.11.Final.jar:5.3.11.Final]
// at org.hibernate.collection.internal.AbstractPersistentCollection.write(AbstractPersistentCollection.java:408) ~[hibernate-core-5.3.11.Final.jar:5.3.11.Final]
// at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:386) ~[hibernate-core-5.3.11.Final.jar:5.3.11.Final]
// at com.toffeestory.backend.post.Post.setAccount(Post.java:55) ~[main/:na]
// at com.toffeestory.backend.post.PostController.enrollPost(PostController.java:55) ~[main/:na]

답변 2

3

백기선님의 프로필 이미지
백기선
지식공유자

Account 객체의 상태가 Detached 상태기 때문에 LazyLoading을 할 수 없어서 에러가 나는겁니다. @Transactional 안에서 코드를 실행하시면 잘 동작할 겁니다. 

제 강좌는 JPA에 대한 강좌는 아니지만 강좌 중에 분명 객체의 상태에 대해 설명한 수업이 있었던 걸로 기억합니다. 해당 부분을 복습해 보시길 추천드립니다.

0

감사합니다

건후레이크님의 프로필 이미지
건후레이크

작성한 질문수

질문하기