포스트

2022-03-10-TIL

Today I Learned

연관관계 테이블

연관관계를 맺는 테이블이 있는게 나을까? 아니면 그냥 외래키를 두어서 참조하는 형태가 나을까?

관계의 다중성에 따라 답이 갈린다. 일대다 관계는 “다” 쪽 테이블에 외래 키를 두는 것으로 충분하고, 별도 관계 테이블을 두면 조인만 하나 늘어난다. 다대다 관계는 관계형 테이블 두 개로 직접 표현할 수 없으므로 중간 테이블이 반드시 필요하다. 이때 JPA의 @ManyToMany와 @JoinTable로 중간 테이블을 숨길 수도 있지만, 중간 테이블에 등록일이나 순서 같은 컬럼이 붙는 순간 매핑할 곳이 없어진다. 그래서 실무에서는 중간 테이블을 엔티티로 승격시켜 @ManyToOne 두 개로 푸는 방식을 많이 쓴다.


관계 테이블이 있을때 QueryDSL 조인

1

@JoinTable로 매핑된 다대다 관계는 QueryDSL에서 중간 테이블을 직접 다루지 않고, 엔티티의 컬렉션 경로로 조인한다. 링크된 질문의 해결 방법도 같은 방식이다.

1
2
3
4
5
6
7
8
QUser user = QUser.user;
QRole role = QRole.role;

List<User> admins = queryFactory
        .selectFrom(user)
        .join(user.roles, role)
        .where(role.name.eq("ADMIN"))
        .fetch();

JPA가 user.roles 경로를 보고 중간 테이블을 거치는 SQL 조인을 만들어 준다.

  • https://stackoverflow.com/questions/67217677/solved-how-to-join-jointable-using-querydsl

연관관계 없이 Join

엔티티 사이에 연관관계 매핑이 없어도, Hibernate 5.1 이상과 QueryDSL 4.x 조합에서는 on 절로 임의의 엔티티를 조인할 수 있다. 연관관계 경로 없이 join(team).on(member.teamName.eq(team.name))처럼 루트 엔티티를 바로 조인 대상으로 넘긴다. 연관관계를 억지로 추가하지 않고 로그 테이블이나 코드 테이블을 붙일 때 유용하다.

  • https://jojoldu.tistory.com/396

쿼리 결과 프로젝션

조회 결과로 엔티티 전체가 아니라 필요한 컬럼만 가져오는 것을 프로젝션이라고 한다. 컬럼이 하나면 그 타입으로, 여러 개면 QueryDSL의 Tuple로 받을 수 있지만, Tuple은 QueryDSL 타입이라 리포지토리 밖으로 내보내지 않는 편이 좋다. DTO로 받을 때는 다음 방법이 있다.

  • Projections.bean: 기본 생성자와 setter로 값을 채운다.
  • Projections.fields: 필드에 직접 값을 넣는다. setter가 필요 없다.
  • Projections.constructor: 생성자 파라미터 순서대로 넣는다.
  • @QueryProjection: DTO 생성자에 붙이면 Q 타입이 생성되어 컴파일 시점에 타입을 검사한다. 대신 DTO가 QueryDSL에 의존하게 된다.

  • http://querydsl.com/static/querydsl/3.4.2/reference/html/ch03s02.html

여러개의 테이블 조인

여러 테이블을 조인할 때는 join을 이어 붙이면 된다. 일대다 컬렉션을 여러 개 조인하면 결과 행이 곱해지므로, 필요한 컬럼만 프로젝션으로 가져오거나 컬렉션은 별도 쿼리로 나누어 조회하는 것이 안전하다.

  • https://stackoverflow.com/questions/47701172/how-to-join-multiple-querydsl-tables
  • https://www.baeldung.com/rest-querydsl-multiple-tables

같은 테이블에 대해서 여러개의 엔티티

같은 테이블 하나에 대해서 여러개의 엔티티를 생성하여 사용해도 될까? 동시성이나 트랜잭션의 이슈가 발생하지 않을까?

3월 6일 TIL에서 정리했듯이 매핑 자체는 가능하지만, Hibernate는 두 엔티티가 같은 행이라는 것을 모른다. 한쪽 수정이 다른 쪽에 반영되지 않고, 같은 트랜잭션에서 둘 다 수정하면 낙관적 락 예외가 날 수 있다. 조회 전용이라면 별도 엔티티보다 DTO 프로젝션이 낫다.


Gradle 프로젝트 라이브러리화

여러 프로젝트가 공유하는 코드를 Gradle 라이브러리로 만들어 배포하는 방법이다. java-library 플러그인으로 라이브러리를 빌드하고, maven-publish 플러그인으로 Maven 저장소에 올린다. 로컬에서 시험할 때는 publishToMavenLocal로 ~/.m2에 설치하고 사용하는 쪽에서 mavenLocal()을 저장소로 추가하며, 팀에서 공유하려면 Nexus 같은 사내 저장소에 배포한다.

1
2
3
4
5
6
7
8
9
10
11
12
plugins {
    id 'java-library'
    id 'maven-publish'
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
        }
    }
}
  • https://velog.io/@haerong22/Gradle-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%A7%8C%EB%93%A4%EA%B3%A0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0Maven-Local-Repository
  • https://docs.gradle.org/current/userguide/publishing_maven.html
  • https://docs.gradle.org/current/samples/sample_building_java_libraries.html
  • https://kim-daeyong.github.io/2019-08-26-nexus/

Gradle Compile and Implementation

Gradle 업그레이드 가이드에 따르면 compile과 runtime 설정은 의존성 범위를 세밀하게 나누지 못해서 Gradle 3.4에서 implementation과 api가 대체로 도입되었고, Gradle 7에서는 compile과 runtime이 제거되었다. implementation으로 선언한 의존성은 라이브러리를 쓰는 쪽의 컴파일 클래스패스에 노출되지 않고, api(java-library 플러그인 전용)는 노출된다. java-library 문서는 implementation을 쓰면 전이 의존성에 실수로 기대는 일이 없고, 구현 의존성이 바뀌어도 사용하는 쪽을 다시 컴파일할 필요가 줄어든다고 설명한다.

  • https://compogetters.tistory.com/64

QueryDSL 조회 DTO, Entity

조회 결과를 엔티티로 받을지 DTO로 받을지의 문제다. 엔티티로 조회하면 영속성 컨텍스트가 관리하므로 변경 감지로 수정할 수 있지만, 필요 없는 컬럼과 연관 엔티티까지 다룬다. 링크된 글들은 수정이 목적이면 엔티티로, 화면이나 API 응답처럼 읽기만 하는 조회는 필요한 컬럼만 DTO로 가져오는 것을 권한다.

  • https://jojoldu.tistory.com/518
  • https://cheese10yun.github.io/querydsl-projections/
  • https://roytuts.com/how-to-map-custom-query-results-into-dto-in-spring-data-jpa/

QueryDSL

QueryDSL은 엔티티에서 생성한 Q 타입으로 JPQL을 자바 코드로 작성하게 해 주는 라이브러리다. 문자열 JPQL과 달리 오타나 타입 오류를 컴파일 시점에 잡을 수 있고, where 조건에 null을 넘기면 무시되는 성질을 이용해 동적 쿼리를 깔끔하게 만들 수 있다. Q 타입은 애너테이션 프로세서로 생성하므로 빌드 설정이 필요하다.

  • https://ict-nroo.tistory.com/117
  • https://www.baeldung.com/rest-api-search-language-spring-data-querydsl
  • https://gilssang97.tistory.com/44
  • http://querydsl.com/static/querydsl/latest/reference/html/
  • https://velog.io/@cco2416/Querydsl-%EC%82%AC%EC%9A%A9-%EC%A0%95%EB%A6%AC
참고한 자료외부 출처 3

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다