[목차]

 

1. Response 에 null 값이 뜨는 문제

2. 순환참조 오류

3. cascade 연속성 전이

4. @Transactional 

+ 이번 과제 관련 추가 (발생 가능성이 있었던 문제)

 


1. Response 에 null 값이 뜨는 문제

 

 

1. 이슈

위와 같이 게시글을 입력하고 조회했을 때, 수정시간과 작성시간의 값이 null로 뜨는 문제가 발생했다.

 

2. 발생 이유 

위는 ResponseDto 클래스 생성자 부분이다. 

null값이 뜰 때는 주석처리되어 있는 부분을 작성하지 않은 상태였기 때문에 생성자 초기화가 되어있지 않은 상태인게 문제의 이유였다.

 

3. 해결 

주석처리 했던 부분을 기입했더니 아래와 같이 값이 잘 들어오는 것을 확인할 수 있었다.

 

 

 

  • 같은 조의 미경님도 PostMan으로 게시글 조회부분을 확인하실 때 id값이 들어오지 않는 문제가 있으셨는데, 나와 같은 이유로 Dto부분 생성자 부분에 id 값을 넣어주지 않아서 발생한 문제였다. 
  • 처음에 스프링에 대한 이해가 부족하다 보니, Entity와 Dto 두 가지 차이에 대한 이해가 부족해서 발생한 문제였다.
  • Entity는 DB에 저장되어지는 테이블 값이라고 생각하면 되고, Dto는 내가 원하는 값만 cutomize 해서 request를 받거나 response를 주는 부분이라고 생각하면 쉬울 것 같다. 
  • 따라서 Entity 처럼 모든 항목을 기입할 필요 없이, 게시글을 받는 부분의  RequestDto 부분의 생성자 부분엔 유저로 부터 입력값을 받게될 username, title, content 부분만 넣어주면 되고, 또 화면단으로 반환되는 부분은 ResponseDto 생성자 부분에 password를 제외한 id, username, title, content, modifiedAt, createdAt 등의 값들을 생성자 부분에 넣어주면 된다.

 

2. 순환참조 오류

 

 

1. 이슈 

Post와 Comment를  각각 @OneToMany, @MantToOne 로 양방향 연관관계를 맺어주고 PostMan에서 게시글 조회를 했더니 순환참조오류인 Stack over flow 문제가 발생했다.

보이는 바와 같이 18,562 줄이나 조회가 되었음을 볼 수 있다.

 

Comment Entity
Post Entity

위와 같이 Post Entity 와 Comment Entity 부분에 양방향으로 연관관계가 맺어져 있다.

Comment Entity

2. 발생이유

그리고 위와 같이 Comment Entity 자체에 post 값이 들어가 있는데,

게시글을 조회하는 과정에서 그 밑에 연관관계로 맺어진 Comment List가 딸려오고, 

그 딸려온 Comment 안에 또 모든 post값이 들어가기 때문에 돌고 돌아버리는 순환참조 오류가 발생한 것이다.

 

 

3. 해결 방법 (2 가지)

3-1. @JsonIgnore을 사용한다.

Post Entity 부분

  • 당장의 순환참조 오류는 해결했지만, 완전한 방법은 아니다.
  • 임시방편이라고 할 수있다.

 

3-2. Dto부분의 설계를 잘 한다.

PostResponseDto 부분

  • List<> 안의 제네릭 부분을 Comment 엔티티로 하지 말고 Dto로 변환한뒤, 다시 배열을 만들어 Comment(Response)Dto 값들을 넣어준다.
  • 배열을 변환해주는 과정은 Dto 혹은 Service단 모두 가능하지만, 일단 아래와 같이 Service 단에서 실행해 주었다.

 

PostService 게시물 전체조회 부분

  • 이중 for each 반복문으로 CommentDto의 값이 들어간 commentList를 만들어 주고, 다시 그 댓글 리스트를 게시글 리스트에 넣어주었다. 

해결후 제대로 Response 값이 찍힘

 

  • 양방향 연관관계를 맺을 땐 항상 순환참조 오류를 조심해야 한다.
  • 이를 방지하기 위해 Dto설계를 견고히 하자.

[무한 순환참조 참고자료] : https://subji.github.io/posts/2020/08/06/infiniterecusionofjpa

 

3. cascade 연속성 전이

PostMan 게시글 삭제 오류
콘솔창 에러 메세지

1. 이슈

게시글과 댓글이 일대다 양방향 연관관계로 매핑되어 있는 상태에서 댓글을 삭제할 땐 오류가 없지만, 게시글을 삭제할 경우 오류가 발생

 

2. 발생이유 : 영속성 전이 문제

 

영속성 전이란?

부모 엔티티가 영속화될 때 자식 엔티티도 같이 영속화되고, 부모 엔티티가 삭제될 때 자식 엔티티도 삭제되는 등 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 전이되는 것을 의미

즉, 특정 엔티티에 대해 특정한 작업을 수행하면 관련된 엔티티에도 동일한 작업을 수행한다는 의미입니다.

 

CascadeType는 코드와 같이 PERSIST, MERGE, DETACH, PREFRESH, REMOVE, ALL 로 구성되어 있다.

각각의 operations에 대한 설명은 다음과 같다.

  • CascadeType.ALL: 모든 Cascade를 적용
  • CascadeType.PERSIST: 엔티티를 영속화할 때, 연관된 엔티티도 함께 유지
  • CascadeType.MERGE: 엔티티 상태를 병합(Merge)할 때, 연관된 엔티티도 모두 병합
  • CascadeType.REMOVE: 엔티티를 제거할 때, 연관된 엔티티도 모두 제거
  • CascadeType.DETACH: 부모 엔티티를 detach() 수행하면, 연관 엔티티도 detach()상태가 되어 변경 사항 반영 X
  • CascadeType.REFRESH: 상위 엔티티를 새로고침(Refresh)할 때, 연관된 엔티티도 모두 새로고침

2. 해결 방법

  • cascade = CascadeType.REMOVE 를 코드를 추가 !

 

  • 코드 추가 후 게시글이 잘 삭제되는 것을 확인 !

[영속성 전이 참고 자료] : https://zzang9ha.tistory.com/350

 

4. @Transactional 

1. 이슈

게시글 댓글 수정이 PostMan response 부분에 문제없이 처리가 되었다고 뜨는데, h2 콘솔 데이터베이스를 확인하면 데이터 변환이 일어나지 않음.

 

Comment Service 파일

 

PostMan에는 수정사항이 잘 반영되었다.
h2-console

그러나 h2-console 에는 수정이 반영되지 않았다.

 

2. 발생 이유

update 메소드에 @Transattilnal 어노테이션이 빠졌다.

Comment Service update 부분
수정 후 h2-console

3. 해결방법 : update 메소드에 @Transattilnal 어노테이션 추가

위와 같이 정상적으로 업데이트가 되는 것을 확인 할 수 있다. -> 이부분은 스프링 트랜스잭션 개념으로 다시 정리 할 것 !  :) 

 

+ 이번 과제 관련 추가 (발생 가능성이 있었던 문제)

① N+1 문제

 

연관 관계에서 발생하는 이슈로 연관 관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수(n) 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오게 된다. 이를 N+1 문제라고 한다.

  • N+1은 JPA를 사용하면서 연관관계를 맺는 엔티티를 사용한다면 한번 쯤은 부딪힐 수 있는 문제이다.
  • Fetch Join이나 EntityGraph를 사용한다면 Join문을 이용하여 하나의 쿼리로 해결할 수 있지만 중복 데이터 관리가 필요하고 FetchType을 어떻게 사용할지에 따라 달라질 수 있다.
  • SUBSELECT는 두번의 쿼리로 실행되지만 FethType을 EAGER로 설정해두어야 한다는 단점이 있다.
  • BatchSize는 연관관계의 데이터 사이즈를 정확하게 알 수 있다면 최적화할 수 있는 size를 구할 수 있겠지만 사실상 연관 관계 데이터의 최적화 데이터 사이즈를 알기는 쉽지 않다.
  • JPA 만으로는 실제 비즈니스 로직을 모두 구현하기 부족할 수 있다. JPA는 만능이 아니다. 간단한 구현은 JPA를 사용하여 프로젝트의 퍼포먼스를 향상 시킬수 있겠지만 다양한 비즈니스 로직을 복잡한 쿼리를 통해서 구현하다보면 다양한 난관에 부딪힐 수 있다. 그리고 불필요한 쿼리도 항상 조심해야 한다. 그러므로 QueryBuilder를 함께 사용하는 것을 추천한다. 그러면 생각보다 다양한 이슈를 큰 고민없이 바로 해결할 수 있다.

[참고 자료] https://incheol-jung.gitbook.io/docs/q-and-a/spring/n+1 

 

② @JoinColunm이 꼭 필요한가 ?

 

다대일 연관관계에서 @JoinColumn(name) 옵션은 컬럼 이름 매핑에 사용되는 어노테이션이지, 연관관계에는 아무런 영향이 없다. 단, 조인 대상 컬럼을 변경하기 위해 @JoinColumn(referencedColumnName) 어노테이션을 활용할 수 있다! 그러니 무조건적으로 @JoinColumn을 생략해선 안되겠다.

 

다대일 연관관계 매핑에서만 그렇다. 일대다 단방향 연관관계 매핑에서는 @JoinColumn 어노테이션을 꼭 명시해주어야 한다. 그렇지 않을 경우 중간 테이블을 자동으로 생성한다.
또, 일대다 양방향 연관관계를 매핑하는 방식에서도 연관관계의 주인을 일(1)에게 주려 하는 경우 다(N) 쪽에 @JoinColumn(insertable = false, updatable = false)를 사용하면서 연관관계의 주인을 강제시키는 방법으로도 사용할 수 있다.

즉, 정리하자면 @JoinColumn 어노테이션은 원래 여러가지 옵션을 제공하고 할 수 있는 일이 많다. 그러나 다대일 연관관계 매핑에서는 JPA가 기본적으로 취하는 전략들이 있기 때문에, @JoinColumn 어노테이션을 생략해도 기대하는 대로 동작한다.

 

 

[참고 자료] : https://hyeon9mak.github.io/omit-join-column-when-using-many-to-one/

+ Recent posts