728x90
좋은 질문이에요! 우선, 코드에 나온 두 개의 @Query는 JPQL (Java Persistence Query Language) 을 사용한 예제입니다. 하지만, JPQL뿐만 아니라 네이티브 쿼리, MyBatis 쿼리, QueryDSL 등 여러 방식으로 데이터베이스 쿼리를 작성할 수 있습니다. 각각의 차이를 살펴볼게요.
1. JPQL (Java Persistence Query Language)
- 코드에 작성된 @Query는 JPQL을 사용한 것입니다.
- JPQL은 엔티티 객체 기준으로 작성하는 쿼리이며, SQL과 문법이 유사하지만 DB 테이블이 아니라 JPA 엔티티를 기준으로 쿼리를 작성합니다.
- JPQL을 사용하면 데이터베이스에 종속되지 않고 ORM (Object Relational Mapping) 방식으로 객체를 다룰 수 있습니다.
예시 코드 분석
@Query("SELECT COALESCE(MAX(df.sequence), 1) FROM DownloadFile df WHERE df.downloadFolder.downloadFolderID = :folderID")
Integer findMaxSequenceByFolder(@Param("folderID") String folderID);
- DownloadFile 엔티티를 기준으로 쿼리를 작성함 (DB 테이블명이 아니라 엔티티 클래스명 사용)
- df.downloadFolder.downloadFolderID처럼 객체 관계를 직접 탐색 가능
- 특정 디렉터리(folderID)에서 가장 큰 sequence 값을 찾음
@Query("""
SELECT a FROM Asset a
LEFT JOIN FETCH a.stencil2D s
LEFT JOIN FETCH s.shape2Ds sh
LEFT JOIN FETCH sh.textProps tp
LEFT JOIN FETCH sh.imageProps ip
LEFT JOIN FETCH sh.portProps pp
WHERE a.group.groupID = :groupID
""")
List<Asset> findAllByGroup_GroupID(String groupID);
- LEFT JOIN FETCH를 사용하여 연관된 엔티티를 한 번에 가져옴 → N+1 문제 방지
- Asset 객체를 기준으로 stencil2D, shape2Ds, textProps 등을 한 번에 조회
📌 장점
- JPA 엔티티를 기준으로 작성하므로 객체지향적인 개발 가능
- 데이터베이스 벤더(Oracle, MySQL 등)에 덜 의존적
📌 단점
- 복잡한 쿼리를 작성하기 어렵고, 동적 쿼리를 만들기 힘듦
2. 네이티브 쿼리 (Native Query)
- JPQL과 달리 SQL을 직접 작성하여 실행하는 방식입니다.
- @Query에 nativeQuery = true 옵션을 추가하면 네이티브 SQL을 사용할 수 있습니다.
예제
@Query(value = "SELECT MAX(sequence) FROM download_file WHERE download_folder_id = :folderID", nativeQuery = true)
Integer findMaxSequenceByFolder(@Param("folderID") String folderID);
📌 장점
- SQL을 그대로 사용하므로 복잡한 쿼리 작성 가능
- DBMS의 특정 기능 (예: JSON, 윈도우 함수 등) 활용 가능
📌 단점
- 특정 DB에 종속될 가능성이 있음 (MySQL → Oracle로 변경 시 쿼리 수정 필요)
- 엔티티가 아닌 결과 매핑 처리가 필요함 (@SqlResultSetMapping 사용)
3. QueryDSL
- JPQL보다 더 유연하고 동적인 쿼리 작성이 가능하도록 도와주는 프레임워크
- 메서드 체이닝을 사용하여 가독성이 높은 쿼리 작성 가능
- QClass를 이용하여 컴파일 타임에 문법 오류 체크 가능
예제
QAsset asset = QAsset.asset;
QStencil2D stencil2D = QStencil2D.stencil2D;
JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
List<Asset> assets = queryFactory.selectFrom(asset)
.leftJoin(asset.stencil2D, stencil2D).fetchJoin()
.where(asset.group.groupID.eq(groupID))
.fetch();
📌 장점
- 동적 쿼리 작성 가능 (if문으로 조건 추가 가능)
- 타입 안전성 보장 (컴파일 타임에 검증 가능)
- fetchJoin()을 활용하면 성능 최적화 가능
📌 단점
- QueryDSL을 사용하려면 별도 설정이 필요함
- 초기 러닝커브가 있음
4. MyBatis
- SQL Mapper로, XML 또는 어노테이션을 사용하여 SQL을 직접 작성하는 방식
- JPA와 달리 ORM을 활용하는 것이 아니라 SQL을 직접 실행하고, 결과를 객체에 매핑하는 방식
예제
<select id="findMaxSequenceByFolder" resultType="Integer">
SELECT COALESCE(MAX(sequence), 1)
FROM download_file
WHERE download_folder_id = #{folderID}
</select>
📌 장점
- SQL을 자유롭게 작성 가능 (복잡한 쿼리에 강함)
- 결과 매핑을 직접 설정할 수 있어 최적화가 쉬움
- DBMS 종속적인 기능 사용 가능 (Stored Procedure, JSON 함수 등)
📌 단점
- SQL을 직접 관리해야 하므로 유지보수 부담 증가
- MyBatis로 작성한 쿼리는 자동으로 변경 감지가 불가능 (JPA처럼 자동 업데이트 X)
정리: 언제 어떤 방식이 좋을까?
방식 특징 추천 경우
JPQL | 엔티티 기반 쿼리 | 객체 중심 개발, 간단한 조회 |
네이티브 쿼리 | SQL 직접 사용 | 복잡한 SQL, 성능 최적화 필요 |
QueryDSL | 동적 SQL 생성, 타입 안전 | 동적 쿼리 필요, 유지보수성 중요 |
MyBatis | XML/어노테이션 기반 SQL | JPA보다 SQL을 직접 컨트롤해야 할 때 |
✔ JPA 기반 프로젝트라면 JPQL 또는 QueryDSL을 추천
✔ 복잡한 SQL 최적화가 필요하면 네이티브 쿼리 또는 MyBatis 고려
✔ 동적 쿼리가 많다면 QueryDSL 활용
각 방식은 장단점이 있으니, 프로젝트 특성에 맞게 선택하면 됩니다! 😊
'DB' 카테고리의 다른 글
[MSSQL] Generate Scripts 이용하여 DB 복사 및 적용 (0) | 2025.04.30 |
---|---|
[MyBatis] null 처리 (1) | 2025.02.19 |