JPQL
- Table 이 아닌 Entity(객체) 기준으로 작성하는 쿼리를 JPQL이라고 하며 이를 사용할 수 있도록 EntityManger 또는 @Query 구현체를 통해 JPQL 쿼리를 사용할 수 있다.
JQL : Entity 명으로 쿼리짤때 쓰이는 언어 (쓰이는 곳. JPQL, QueryDSL)
SQL : Table 명으로 쿼리짤때 쓰이는 언어 (쓰이는 곳. JDBC, SQL Mapper)
EntityManager.createQuery()
- 쿼리 문자열과 Entity 를 직접 넣어서 쿼리를 작성한다.
- setParameter 와 같이 key, value 문자열을 통해서 쿼리 파라미터를 매핑할 수 있다.
코드에 문자열이 들어가는게 안 좋은 이유
- 문자열은 오타가 발생할 여지가 많다.
- 개발할때 같은 공통적인 문자열이 있을 때 한 군데에서 수정이 일어나면 모두 수정해야 한다.
- 잘못된 코드가 있더라도 문자열 자체를 컴파일러가 검사하지는 않기 때문에 컴파일 시점에 잡지 못한다.
- 이로 인해 버그가 있더라도 메서드를 실행하는 시점인 런타임시점에 버그가 발생한다.
- 런타임 시점에 발생한 버그는 서비스 정합성에 영향을 주며 원인을 찾기도 어렵다.
해결방법
- 문자열을 포함하여 구현된 기능들은 객체화 또는 함수화 해서 컴파일 시 체크되도록 한다.
- 문자열로 선언된 변수들은 상수로 선언하여 공통적으로 관리한다. (상수 클래스를 사용하면 좋다)
@Query (repository interface)
- @Query의 인자값으로 간단하게 쿼리작성이 가능하다.
- 쿼리를 작성할 때는 테이블명이 아닌 Entity명으로 조회한다.
QueryDSL (JPAQueryFactory)
- Entity의 매핑정보를 활용하여 쿼리에 적합하도록 쿼리 전용 클래스(Q클래스)로 재구성해주는 기술
- 여기에 JPAQueryFactory을 통한 Q클래스를 활용할 수 있는 기능들을 제공한다.
@DynamicInsert
- 이 어노테이션을 엔티티에 적용하게 되면 Insert 쿼리를 사용할 때 null 인 값은 제외하고 쿼리문이 만들어진다.
@DynamicUpdate
- 이 어노테이션을 엔티티에 적용하게 되면 Update 쿼리를 사용할 때 null인 값은 제외하고 쿼리문이 만들어진다.
Projection의 기능
- 원하는 필드만 지정해서 조회 가능
- 여러 필드 합쳐서 재정의 필드(Alias) 조회 가능 (Nested 프로젝션)
- 조회 필드 그룹을 인터페이스 또는 클래스로 만들어놓고 재사용이 가능하다.
Projection 필드 사용방법
1. get필드() 메서드로 정의
- 정의한 필드만 조회하기 때문에 Closed 프로젝션이라고 한다.
- 쿼리를 줄이므로 최적화할 수 있다.
- 메서드 형태이기 때문에 Java 8의 메서드를 사용해서 연산을 할 수 있다.
2. @Value로 정의
- 전체 필드를 조회할 수밖에 없어서 Open 프로젝션이라고 한다.
- @Value(SpEL)을 사용해서 연산을 할 수 있다.
- 스프링 빈 들의 메서드도 호출 가능하다.
- SpEL을 엔티티 대상으로 사용하기 때문에 쿼리 최적화를 할 수 없다.
TestContainers
- 도커 환경에서 데이터베이스를 실행하여 테스트 환경을 쉽게 구축할 수 있게 해주는 라이브러리
- 개발 환경에 데이터베이스를 사용하지 않기 때문에 테스트 때문에 발생하는 더미 데이터를 줄일 수 있다.
- H2와 같은 인메모리 DB를 사용하는 것이 아니라서 실제 환경과 거의 비슷한 환경으로 데이터베이스를 테스트할 수 있다.
- 테스트가 느려지는 단점이 있다.
FixtureMonkey
- 네이버에서 만든 테스트 생성 객체를 자동으로 생성해 주는 자바 라이브러리
- Mock 객체를 보다 쉽게 생성하기 위해서 사용
테스트 정리
단위 테스트
- 각 계층(클래스) 별로 테스트 케이스 작성
통합 테스트
- 실행될 때마다 랜덤 하게 변경되는 시나리오를 만들고 그에 따른 데이터를 미리 생성(Docker 환경의 데이터베이스)
- 모든 엔드포인트에 대해서 테스트
- 사전에 데이터를 미리 만들어둔 것을 통해서, 결과를 예측하고 검증할 수 있음
- 단위테스트는 Pull Request에서 검증하는 용도(CI)
- 통합테스트는 정기 배포 당일 생성한 브랜치에 대해서 검증하고 검증이 완료된다면 자동으로 배포하는 프로세스(CD)
Propagation (전파 전략)
PROPAGATION_REQUIRED (JpaTranscationManager Default)
부모 트랜잭션이 존재할 경우
- 부모 트랜잭션에 참여한다.
부모 트랜잭션이 없을 경우
- 새 트랜잭션을 시작한다.
일반적으로 사용되는 트랜잭션의 전파 유형이다. 어떻게 해서든 Transcation을 시작하는 전파 유형
PROPAGATION_SUPPORTS
부모 트랜잭션이 존재할 경우
- 부모 트랜잭션에 참여한다.
부모 트랜잭션이 없을 경우
- non-transactional 하게 동작한다.
부모를 따라서 전파되는 유형
PROPAGATION_MANDATORY
부모 트랜잭션이 존재할 경우
- 부모 트랜잭션에 참여한다.
부모 트랜잭션이 없을 경우
- Exception이 발생한다.
트랜잭션에 참여하도록 강제하는 유형
PROPAGATION_REQUIRES_NEW
부모 트랜잭션 유무에 상관없이
- 새 트랜잭션을 시작한다.
부모 트랜잭션이 존재할 경우
- 부모 트랜잭션을 중지시킨다.
무조건 새 트랜잭션을 생성하도록 강제하는 유형
PROPAGATION_NOT_SUPPORTED
부모 트랜잭션 유무에 상관없이
- non-transactional 하게 동작한다.
부모 트랜잭션이 존재할 경우
- 부모 트랜잭션을 중지시킨다.
PROPAGATION_NEVER
부모 트랜잭션이 존재할 경우 Exception이 발생한다.
항상 non-transcational 하게 동작하는 유형
N + 1 문제
- 엔티티 하나를 조회하기 위해서 1:N으로 연관된 엔티티까지 조회해서 쿼리문이 N+1번 날아가는 문제
이로 인해 아래와 같은 시스템에 심각한 성능 저하가 일어날 수 있다
/ Comment 조회 - 1번
/ Comment의 개수(각 Comment가 가지고 있는 Board 조회) - N번
이렇게 하면 N+1번의 쿼리가 발생하는 것이다
N + 1 문제 해결방법 3가지
- GlobalFetch
- Fetch Join
- EntityGraph
GlobalFetch
- 글로벌 패치 전략이란, 엔티티를 생성할 때(컴파일 시점) 결정되는 연관관계 전략이다
- 해결방법은 @ManyToOne 속성에 fetch 속성으로 LAZY를 주면 된다
Fetch Join
- 조인할 때 연관된 엔티티나 컬렉션을 함께 조회하려고 할 때 사용한다 결과는 EAGER와 똑같지만 과정은 다르다 EAGER의 경우에는 N+1 쿼리가 발생하지만 Fetch Join의 경우에는 한 번이 쿼리문으로 해결이 가능하다
- Spring Data JPA에서는 @Query 어노테이션을 이용하여 JPQL를 생성할 수 있다
- 사용하는 방법은 위와 동일하게 join fetch 뒤에 연관된 엔티티나 컬렉션을 적어주면 된다
EntityGraph (+ QueryDSL과 더불어 중요)
- @EntityGraph도 마찬가지로 EntityGraph 상에 있는 Entity들의 연관관계 속에서 필요한 엔티티와 컬렉션을 함께 조회하려고 할 때 사용한다.
- Spring Data JPA에서 적용하려는 메서드 위에 @EntityGraph 어노테이션을 달고 옵션을 준다
- attributePaths는 같이 조회할 연관 엔티티명을 적으면 된다.
- , (콤마)를 통하여 여러 개를 줄 수도 있다
'Back-End > Spring (SpartaCC)' 카테고리의 다른 글
[Spring] 자주 사용하는 Annotation (개인적) (0) | 2023.07.27 |
---|---|
[Spring] JPA - SpringData, JpaRepository, QueryDSL (0) | 2023.07.27 |
[Spring] JPA - ORM의 배경, Raw JPA 기능 (0) | 2023.07.27 |
[Spring] 스파르타코딩클럽 Spring공부(6) - OAuth, 단위테스트, 통합테스트, 예외처리관리 (1) | 2023.07.10 |
[Spring] 스파르타코딩클럽 Spring공부(5) - Validation, Entity 관계 (0) | 2023.06.23 |
남건욱's 공부기록