문제 상황
현재 Grammar와 GrammarBook를 N:1 양방향 연관관계로 설정한 상태입니다. 그래서 GrammarBook에 다음과 같이 mappedBy 설정으로 GrammarBook은 연관관계의 주인이 아님을 명시해뒀습니다.
@OneToMany(mappedBy = "grammarBook", cascade = CascadeType.ALL)
@OrderColumn(name = "id")
private List<Grammar> grammars = new ArrayList<>();
그리고 GrammarBook엔티티 객체에서 grammars로 size()
를 호출하니 수많은 Grammar엔티티 값과 함께 수많은 null값이 채워져 반환되었습니다.
[null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null,
grammar id: 16, sentence: I _ Emma. I _ from New York., book name: 과거와 과거진행,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null,
grammar id: 145, sentence: Patricia _ single last year, but now she's married., book name: 과거와 과거진행,
grammar id: 146, sentence: We _ at home all day yesterday. We _ very bored., book name: 과거와 과거진행,
grammar id: 147, sentence: _ you busy yesterday?, book name: 과거와 과거진행,
grammar id: 148, sentence: _ Tom at the park this morning?, book name: 과거와 과거진행,
grammar id: 149, sentence: The museum _ open last Wednesday. It was a holiday., book name: 과거와 과거진행,
grammar id: 150, sentence: I _ a new sofa last week., book name: 과거와 과거진행,
grammar id: 151, sentence: I _ at home last weekend. I went out with my friends., book name: 과거와 과거진행,
grammar id: 152, sentence: Some kids _ in the pool a few minutes ago., book name: 과거와 과거진행,
grammar id: 153, sentence: _ it _ when you arrived?, book name: 과거와 과거진행]
잘 보면 grammar id 가 없는 데이터가 null로 채워져있습니다.
원인
2회 이상의 fetch join을 하기위해 GrammarBook의 grammars필드에 붙여둔 @OrderColumn
때문입니다.
@OneToMany(mappedBy = "grammarBook", cascade = CascadeType.ALL)
@OrderColumn(name = "id")
private List<Grammar> grammars = new ArrayList<>();
@OrderColumn
은 데이터베이스에 순서값(POSITION)을 따로 저장해서 조회할때 사용합니다.
- POSITION은 N:1 관계에서 N 쪽에 저장됩니다.
- 하지만 POSITION이 1 쪽에서 관리되기 때문에 N 쪽은 POSITION에 접근하지 못합니다. 그래서 N 쪽의 엔티티 객체를 삽입시 POSITION을 수정하는 update 쿼리가 추가로 발생합니다.
- 레코드가 하나만 삭제되도 그 뒤 레코드들의 POSITION이 모두 update됩니다.
- 중간에 POSITION이 비면 해당 위치에 null이 보관된 컬렉션(위에서 List<Grammar>)가 반환됩니다.
해결
현재로서는 fetch join을 2회 이상 수행하는 쿼리를 나누거나, Grammar쪽에서 grammar들을 가져오는 방법이 있습니다.
아무래도 빈 POSITION 레코드는 null로 채워진다는 점이 걸려 fetch join을 나누기로 했습니다.
'Springboot' 카테고리의 다른 글
[트러블 슈팅]N+1 해결하기 (1) (0) | 2024.02.24 |
---|---|
[트러블 슈팅]LazyInitializationException 간단 해결법 (0) | 2024.02.24 |
N : 1 단방향 연관 관계에서 더 나은 조회 쿼리 (0) | 2024.02.21 |
[트러블 슈팅]fetch join 2번 이상 사용시 `MultipleBagFetchException`발생 (0) | 2024.02.21 |
스프링부트 테스트 시 리액트 앱 빌드 건너뛰기 (0) | 2024.02.03 |