인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

퓨퓨님의 프로필 이미지

작성한 질문수

스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판

댓글 최대 2 depth - CUD API 구현

안녕하세요. 실무에서 JPA 사용법

해결된 질문

작성

·

296

0

 

  1. 안녕하세요. 강의 잘 수강하고 있습니다. 현재 회사에서 MyBatis를 주로 사용하고 있습니다. 제가 JPA에 대한 실무 경험이 없다보니 실무에서는 어떻게 JPA를 사용하는지 궁금하여 질문을 드렸습니다.

 

질문

  1. 제가 생각할 때 이번 프로젝트는 복잡한 부분이 없어서 단순히 연관 관계가 필요 없다고 생각하는데 복잡한 실무에서 연관관계를 사용하는지 유무가 궁금하다. (상황마다 다르겠지만 일반론 기준)

 

  1. 거의 모든 Repository에서 네이티브 쿼리를 사용을 하였는데 실무에서 native Query를 많이 사용하는지 궁금하며 QueryDsl은 실무에서 어떤 방식으로 사용하는 궁금합니다. ( 크게 런타임 타입 체킹이 필요가 없다면 거의 다 native Query로 풀 수 있을거 같은데 QueryDSL을 사용한 경험을 듣고 싶습니다.

답변 2

2

쿠케님의 프로필 이미지
쿠케
지식공유자

퓨퓨님, 안녕하세요!

 

강의 잘 수강해주셔서 감사합니다!!

질문 주신 내용도 아주 좋은 고민입니다!

 

일단 조금 아쉬운 답변일 수 있는데,

실무에 들어가면 팀의 선택에 따라 JPA를 사용하지 않는 상황도 아주 많습니다.

 

JPA를 학습하고 적용하는게 오히려 더 복잡해질 수 있기 때문에,

개인적으로도 단순 CRUD 외 복잡한 상황에서는 JPA를 사용하지 않습니다.(단순 CRUD 조차도 잘 안쓰긴 합니다.)

또, 단순 CRUD를 쓴다면 매퍼(객체<->쿼리결과 변환) 기능만으로도 충분하기 때문에,

애초에 러닝커브를 감수하면서까지 JPA를 사용할 이유가 없어지기도 하고요.

 

강의에서는 JPA가 수강생 분들에게 익숙하게 다가올 것 같아서 채택하였지만,

사실 ORM으로써 사용했다기보단 단순 매퍼 기능으로 사용하고자 한 의도가 컸습니다.

그렇기 때문에 강의 소개에서도 JPA를 몰라도 수강할 수 있다는 부분을 언급드리고 있는 것이고,

JPA에 종속된 생각은 벗겨내고 DB 관점에서 생각하는게 이해가 편하실 수 있을 것 같습니다!

 

제 말들이 JPA에 부정적으로 다가올 수 있는데, 그 이유는 아래 답변들을 통해 조금씩 해소될 수 있을 것 같습니다.

 

1.

일단 프로젝트의 복잡도와 무관하게, 연관 관계는 모두 필요하고, 설정되어 있다고 볼 수 있습니다.

코드(JPA의 @ManyToOne 등) 또는 테이블 제약 조건 같이 물리적으로 드러나지 않을 뿐이지, 논리적으로는 모두 연관 관계가 필요합니다.

예시로, comment 테이블은 article 정보를 알기 위해 articleId를 외래키로 가지고 있습니다.

이 값은 어떠한 제약조건도 없이 단순히 BIGINT 타입으로 설정되어 있고, 코드에서도 별다른 설정이 없어보여서 연관관계가 없다고 봐야하는건지 헷갈리실 수 있을 것 같습니다.

하지만 테이블 간에 참조 키를 가지고 있는 것만으로도 연관 관계가 설정되어 있다고 볼 수 있습니다.

(결국 comment 테이블이 article을 찾기 위해 articleId를 가지고 있는 상황이 연관 관계를 가지고 있는 것)

 

코드 또는 테이블 제약이 없는 이유를 설명드리면 좋을 것 같은데요, 아래 내용 참고 부탁드립니다!

 

일단 트래픽이 많을 때 테이블 제약 조건은 걸지 않는게 일반적입니다.

테이블 제약 조건으로 인해 스키마 변경을 쉽게 수행하기 어려운 상황이 만들어질 수도 있고(테이블 관리 비용),

데이터 CUD 작업 시에 제약 사항을 확인하기 위해 데이터베이스에서 부가적인 비용 또는 락이 생길 수 있습니다(성능 비용).

따라서, 단순히 외래키를 가지고는 있을 뿐이지, 성능 및 테이블 관리 차원에서 테이블 제약 조건(외래키 등)은 걸지 않는 경우가 많습니다.(논리적으로 연관 관계가 설정되어 있다고 봄)

 

또, 강의에서는 MSA를 지향하며 데이터베이스도 분산되어 있다는 관점입니다.

현재 외래키가 직접적으로 걸려있지도 않고, 애초에 데이터베이스 자체도 분산되어 있기 때문에 테이블 제약 조건이나 JPA의 @ManyToOne 같은 제약조건은 사용할 수 없습니다.(정말 필요하다면, 여러 DB 간에 지원하도록 부가적인 기능으로 만들어낼 수도 있겠지만)

 

2.

JPA가 알아서 요청을 처리해준다고 해도, 결국 내부적으로는 SQL문으로 처리되는 것은 알고 계실 것 같습니다.

제가 JPA만 학습하신 분들에게 대체로 느낀 바로는,

페이징 처리를 단순히 Pageable만 사용하고 실제 내부 동작에 대해서는 전혀 이해하지 못하고 있는 경우를 자주 봤습니다.

위 쿼리를 쓰면 단순히 offset/limit을 만들어줄 뿐이지, 강의에서 설명하는 최적화된 쿼리로 만들어주진 않습니다.

결국 DB 인덱스에 대한 이해가 있어야 최적화가 가능한 내용이고,

코드에서는 native query로 작성하여 DB에서 실제 실행되는 쿼리가 직관적으로 드러나도록 하는걸 의도했습니다. (JPQL, QueryDSL, Spring Data JPA 사용하지 않고)

이 선택은 수강생 분들의 원활한 학습을 위함이라고 봐주시면 될 것 같고, 아래 내용으로 또 다른 이유도 느껴지실 것 같습니다!

 

QueryDSL은 저도 학습은 해보았으나 실무에서 써본적은 없습니다.(일단 JPA도 잘 안쓰기 때문에)

코드로 작성하기 때문에 컴파일 타임부터 오류를 즉시 확인할 수 있다는 이점은 있으나,

native query든 QueryDSL이든 결국 테스트는 필요할 것이고,

테스트 코드 한번 돌리는 걸로도 문자열 쿼리 검증도 충분히 가능하다라는 생각도 있습니다.

모니터링 관점에서도 native query를 쓰는게 유리할 수 있는데요,

슬로우 쿼리 등 문제가 터졌을 때 DB 입장에서는 native query로 모니터링하게 됩니다.(애플리케이션에서 모니터링 시스템을 별도 구축하지 않았다면)

그런데 QueryDSL같이 쿼리를 자동으로 생성해주는 경우, 대규모 시스템에서는 이 쿼리가 어떤 코드에서 나가고 있는건지 찾는 것도 큰 시간과 노력이 필요할 수 있습니다.(이 문제는 JPQL에서도 동일합니다.)

따라서, 개인적으로는 QueryDSL이든 JPA든 세팅 및 학습 비용에 비해 크게 이점이 안보여서 딱히 사용하는걸 좋아하진 않고, 실무에서 복잡한 쿼리에 대해 적용해본 적은 없습니다.

말씀하신대로 모두 native query로 풀어낼 수 있고, 복잡한 쿼리일수록 이게 오히려 직관적이고 명확하기 때문에 선호하는 부분도 있습니다. (결국 수행되어야 하는건 SQL 쿼리이므로)

 

위 내용들을 보면 JPA를 써야할 이유가 딱히 안보이기도 해서, 실무에서는 JPA를 잘 안쓰게 되네요.

물론, 제 말이 반드시 정답은 아닙니다!

부가적인 비용을 감수하더라도 적용했을 때의 장점(1차 캐시, 더티 체킹 등. 근데 이것도 코드 몇줄이면 동일한 효과로 더욱 유연하게 만들 수도 있다는 생각)도 분명 있고,

사람마다 느끼는 바는 다르므로, 참고 정도로만 받아들여주셔도 좋을 것 같네요!

 

의문이 잘 풀리셨을지 모르겠습니다만..!

혹시 더 궁금한 점 있으시면 편히 문의 주세요!

2

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다. 퓨퓨님.

JPA 사용에 대한 실무에서는 여러 가지 전략과 패턴이 사용될 수 있는데요. 일반적인 실무 경험을 바탕으로 몇 가지 정보를 드리겠습니다.

연관관계 사용 여부

  1. 단순 프로젝트:
    • 연관 관계가 복잡하지 않을 경우, 연관 관계 설정을 최소화하여 단순 조인으로 해결하는 것이 유지보수 측면에서 유리할 수 있습니다.
    • 그러나 실시간 쓰기 및 읽기 성능이 중요한 경우, 연관 관계를 설정해 로딩 전략을 관리하는 것이 유리할 수 있습니다.
  2. 복잡한 도메인 모델:
    • 비즈니스 도메인이 복잡하다면, 객체 간의 관계를 명확히 하기 위해 연관 관계를 적극적으로 설정하는 것이 오히려 장점이 될 수 있습니다.
    • 특히, 지연 로딩과 같은 기능을 통해 성능 최적화에 도움을 줄 수 있습니다.

Native Query 및 QueryDSL 사용

  1. Native Query:
    • Native Query는 주로 성능 최적화가 필요한 경우나 복잡한 쿼리를 사용할 때 유용합니다.
    • DB 종속적인 특성을 가질 수 있어 이식성이나 유지보수에 주의를 기울여야 합니다.
  2. QueryDSL:
    • QueryDSL은 타입 안전성과 동적 쿼리 구성의 편리함을 제공합니다.
    • 특히 복잡한 조건을 구성하는 경우, 코드 가독성을 높이고, 컴파일 시점에 오류를 체크할 수 있어 활용성이 높습니다.

관련한 더 많은 정보는 아래 게시글을 통해 자세히 살펴보실 수 있습니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

퓨퓨님의 프로필 이미지

작성한 질문수

질문하기