inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)

13강. 도메인 계층을 Kotlin으로 변경하기 - UserLoanHistory.java, User.java

JPA 연관관계 질문입니다.

978

opensesame

작성한 질문수 8

1

안녕하세요!

강의는 다 들었는데 JPA 공부를 하다가 궁금한점이 있어서

질문을 남겨봅니다.

현재 User 와 UserLoanHistory 는 1:N 관계이고,

User쪽에 cascade 옵션이 걸려 있는데요.

그러면 User 가 삭제되면 UserLoanHistory 가 삭제될 때

User 와 연관관계가 있는 히스토리의 개수만큼 delete 쿼리가 나갈거 같은데요. 뭔가 비효율적인거 같다는 생각이 들어서 찾아보니 1:N 에서 N 쪽에 @OnDelete(action = OnDeleteAction.CASCADE)

옵션을 주어서 디비단에서 해결하는 방법이 있는거 같긴한데 이걸 쓰는게 맞을지 고민이 되서 질문드립니다.

이 옵션은 왠지 위험해 보이는데... 그럼 cascade 옵션을 안쓰고 respository 에서 deleteAllInBatch 로 N 쪽을 지우고 1을 따로 지우는게 나을지...

질문을 정리해보자면

 

어떤쪽이 더 좋은 선택인지 고민인데 좋은 의견 주시면 감사하겠습니다.

kotlin spring-boot java spring refactoring

답변 1

1

최태현

안녕하세요! opensesame 님~!!! 크으~ 매우 좋은 질문이십니다! 😊

넵넵, 말씀해주신것처럼 cascade 옵션이 전체로 걸려 있으면 delete가 될 때 (정확히는 JPA EntityManager의 remove가 호출 될 때) N쪽 Entity로 remove가 전파되면서 delete 쿼리가 N번 발생하게 됩니다! 때문에 1 : N 연관관계를 만들 때는 데이터 양에 따라 적절한 방법론을 취해야 하지요!

 

프로그래밍에 정해진 정답은 없고, 저의 개인적인 생각이지만 질문 주신 내용에 답변을 드려보자면

 

[N 쪽에 @OnDelete 옵션을 주는 방식이 나을지?]

이 옵션은 제가 사용해보지 않아서 찾아보니 FK를 이용한 DB의 옵션인 것 같았습니다! 동작하는 느낌이 DB의 트리거와 비슷한 것 같은데요~ 저는 객체끼리 연관관계를 맺더라도 DB Table에서는 FK 자체를 사용하지않기도 하고, Trigger, Stored Procedure와 같이 DB의 기능을 지양하는 편이라 아무래도 꺼려지는 것 같습니다!

아마 opensesame님께서도 비슷한 느낌을 "왠지 위험해 보이는데.."라고 표현해주신 것 같아요~ ㅎㅎㅎㅎ

 

[수동으로 N쪽을 삭제하고 1 을 삭제하는게 나을지?]

위의 옵션이 애매하다면, 당연히 이 방법을 사용해야 합니다! 말씀해주신 deleteAllInBatch 는 특정 column을 기준으로 삭제하는게 아니라 연관관계를 무시한채 해당 테이블 전체를 지우는 것이다 보니, 사용하기는 어려울 것 같고요, 저라면 Querydsl에서 delete 쿼리를 적절하게 짤 것 같습니다!! 물론 여기서도 고민해볼 거리는 있습니다!

예를 들어... 1) 1과 N을 같이 삭제하는 것에 대한 문제가 존재할 수 있는지 - 예를 들면 N 쪽의 데이터가 너무 많아 1은 0.01초만에 삭제되고 N은 0.1초만에 삭제된다면 1부터 삭제 시켜서 API에는 OK를 내려주고, N 쪽은 비동기적으로 처리할 수도 있겠죠! 2) 1과 N을 비동기적으로 삭제해도 괜찮은지, 비동기적으로 삭제할 거라면 어떤 방법론을 사용할 것인지 와 같은 고민거리입니다 ㅎㅎㅎㅎ

 

또한, 근본적으로 1 : N 관계에서 N 쪽에 데이터가 꽤 많다면 JPA 연관관계를 꼭 맺어야 하는가도 고민을 해보아야 합니다. 같은 애그리거트라 하더라도, 성능적인 이유로 객체간의 연관관계를 반드시 맺어야 할 필요는 없으니까요..!!

이러한 기술적인 Trade-Off 외에, resource 적인 Trade-Off도 생각해볼 수 있습니다!

사실 1 + N 에서 N이 20~30개 수준이라면 크게 문제되지는 않아요!! 쓰기지연으로 인해 Network I/O를 최소화 할 수도 있고요! 물론 줄이면 좋긴하죠 ㅎㅎㅎㅎ 하지만 이렇게 줄이기 위해 추가적인 resource가 얼마나 들어갈지, 그 resource 대비 가치가 얼마나 있을지도 고민해볼 포인트입니다!!

 

아이고~ 제가 살짝 삼천포로 빠졌군요 ㅎㅎㅎㅎㅎ 결론은 저라면, 후자의 방법을 선택할 것 같습니다! 😊

좋은 질문 주셔서 감사드립니다~~ 편안한 밤 되세요~!! 🙇

 

 

 

 

0

opensesame

항상 좋은 답변 해주셔서 감사합니다.

덕분에 많이 배우고 있습니다.

편안한 밤 되세요!!! 🌕

안녕하세요 혹시 프론트 코드 제공받을 수 있을까요?

0

68

2

실행이 안되네요

0

65

2

프론트 영역 보는법

0

51

2

companion object

0

78

2

Custom 레프직토리 형식

0

57

2

Querydsl 도입

0

67

2

fetch join DISTINCT 중복제거

1

83

2

표준 예외와 커스텀 예외 사용 전략 질문

0

85

3

이 질문이 왜 없는지 이해가 안 되지만 문제 인식 및 해결 방법 남깁니다.

1

177

2

테스트를 위한 코드

1

105

2

프로젝트 실행 에러

0

151

2

PDF 문서에 오타가 있어서 알려드립니다.

1

102

1

enum질문

1

86

1

테스트 후 AfterEach 함수에서 나오는 쿼리

0

136

2

테스트 fixture

1

210

2

./gradlew test 실행시 인식할수 없다고 뜹니다.

0

140

1

test 코드 실행시 경고가 발생합니다.

0

140

1

13강 User Kotlin 변환중

2

169

3

'추가 - 코프링과 플러그인' 강의 7:46 allopen 관련 질문

2

174

1

-

0

141

2

4:28 build.gradle 수정 시 kotlin-reflect관련 implementation 추가 해야할까요?

0

312

3

junit import 불가

0

271

3

테스트 코드와 관련하여 질문이 있습니다.

1

218

1

hibernate가 select를 두번 하는 이유

0

240

1