Java 애플리케이션에서 데이터베이스와 상호작용하기 위해 다양한 기술이 존재하며, 그중 대표적인 것이 JPA, JPQL, QueryDSL, 그리고 Native Query입니다. 각 기술은 고유한 장점과 단점을 가지고 있으며, 상황에 맞게 적절한 방법을 선택하는 것이 중요합니다. 이 글에서는 각 기술의 특징, 장단점, 예제 코드, 그리고 활용할 때의 주의점에 대해 설명합니다.
JPA는 ORM(객체-관계 매핑) 표준으로, 자바 객체와 데이터베이스 테이블을 자동으로 매핑하여 데이터베이스 작업을 더 쉽게 처리할 수 있도록 합니다. 기본적인 CRUD(Create, Read, Update, Delete) 작업은 SQL을 직접 작성하지 않고도 처리할 수 있습니다.
@Entity
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
// getters and setters
}
// EntityManager 사용 예시
Product product = new Product();
product.setName("Laptop");
product.setPrice(1500);
entityManager.persist(product);
JPA는 위와 같이 Entity를 기반으로 데이터를 다룹니다. 별도의 SQL을 작성하지 않아도 기본적인 CRUD 작업을 쉽게 처리할 수 있습니다.
JPQL은 SQL과 유사하지만 객체를 대상으로 쿼리를 작성하는 언어입니다. SQL과 달리 JPQL은 데이터베이스 테이블이 아닌 엔티티(Entity)를 대상으로 하므로 객체 지향적인 쿼리 작성이 가능합니다.
@Query("SELECT p FROM Product p WHERE p.price > :minPrice")
List<Product> findProductsWithPriceGreaterThan(@Param("minPrice") int price);
JPQL은 객체를 기준으로 쿼리를 작성하므로, SQL과는 달리 테이블이 아닌 Product 클래스에 대해 쿼리합니다. :minPrice는 파라미터 바인딩을 사용하여 안전한 쿼리 작성이 가능합니다.
QueryDSL은 동적 쿼리를 안전하게 작성할 수 있도록 지원하는 타입 세이프한 쿼리 빌더입니다. 동적 쿼리 작성이 필요할 때 매우 유용하며, SQL, JPQL 등 다양한 쿼리 언어와 호환됩니다.
QProduct product = QProduct.product;
List<Product> products = queryFactory.selectFrom(product)
.where(product.price.gt(1000))
.fetch();
QueryDSL은 타입 세이프한 쿼리 작성이 가능합니다. QProduct는 Product 엔티티에 대한 메타 모델 클래스입니다. QueryDSL은 메소드 체이닝을 통해 쿼리를 직관적으로 작성할 수 있으며, 조건문 등을 동적으로 구성할 수 있어 유연성이 높습니다.
Native Query는 데이터베이스 고유의 SQL을 직접 사용하여 쿼리를 작성하는 방법입니다. 데이터베이스에 직접 SQL을 작성하여 더 높은 성능 최적화를 할 수 있습니다.
@Query(value = "SELECT * FROM Product p WHERE p.price > :price", nativeQuery = true)
List<Product> findByNativeQuery(@Param("price") int price);
}
Native Query는 데이터베이스의 SQL을 그대로 사용할 수 있습니다. 이를 통해 JPA와 JPQL로는 처리하기 어려운 복잡한 쿼리를 직접 작성할 수 있으며, 성능 최적화를 위해 DBMS의 고유 기능을 활용할 수 있습니다. 그러나 데이터베이스에 종속적이라는 단점이 있습니다.
[비교 정리]
| 구분 | 장점 | 단점 | 사용 |
|---|---|---|---|
| JPA | SQL 작성 불필요 | 성능 문제 발생 가능 | 기본 CRUD 작업에 적합 |
| 객체 지향적 코드 | 학습 곡선 있음 | ||
| JPQL | 객체 중심 쿼리 작성 | 복잡한 SQL 기능 지원 제한 | 간단한 조회나 객체 기반 쿼리 시 적합 |
| 데이터베이스 독립성 | 성능 문제 가능 | ||
| QueryDSL | 동적 쿼리 작성 편리 | 초기 설정 복잡 | 복잡한 조건의 동적 쿼리가 필요할 때 적합 |
| 타입 세이프 | 동적 쿼리 성능 문제 가능 | ||
| Native Query | 성능 최적화 가능 | 데이터베이스 종속성 | 성능 최적화가 필요한 복잡한 쿼리 작성 시 적합 |
| 데이터베이스 고유 기능 사용 가능 | 동적 정렬 및 페이징 한계 있음 |
Reference
https://sproutinghye.tistory.com/63
https://velog.io/@simgyuhwan/%EC%BF%BC%EB%A6%AC-%EB%A9%94%EC%86%8C%EB%93%9C-JPQL-Querydsl-%EC%9A%94%EC%95%BD
https://www.baeldung.com/spring-data-jpa-vs-jpa