Light Blue Pointer
본문 바로가기
Developing/TIL(Develop)

JPA 사용할때 쿼리가 복잡해지는 경우의 해결방안

by Greedy 2024. 5. 15.

JPA(Java Persistence API)를 사용할 때 복잡한 쿼리를 구현하는 데는 여러 방법이 있고 상황에 따라 적절한 방법을 선택해야 한다.

1. JPQL(Java Persistence Query Language)

JPQL은 SQL과 유사한 문법을 사용하여 엔티티 객체를 대상으로 하는 쿼리를 작성할 수 있게 해준다

복잡한 쿼리도 작성할 수 있으며, 데이터베이스 독립성을 유지할 수 있다

javaCopy code
String jpql = "SELECT e FROM Employee e WHERE e.department.name = :deptName AND e.salary > :minSalary";
TypedQuery<Employee> query = entityManager.createQuery(jpql, Employee.class);
query.setParameter("deptName", "IT");
query.setParameter("minSalary", 50000);
List<Employee> result = query.getResultList();

2. Criteria API

Criteria API는 타입 세이프하고 동적인 쿼리를 생성할 수 있도록 도와준다

복잡한 조건과 다이나믹 쿼리를 만들 때 유용하다

javaCopy code
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> employee = cq.from(Employee.class);
Join<Employee, Department> department = employee.join("department");

cq.select(employee)
  .where(cb.and(
      cb.equal(department.get("name"), "IT"),
      cb.greaterThan(employee.get("salary"), 50000)
  ));

TypedQuery<Employee> query = entityManager.createQuery(cq);
List<Employee> result = query.getResultList();

3. Native SQL Query

복잡한 SQL 쿼리를 그대로 사용해야 할 경우, 네이티브 쿼리를 사용할 수 있다

이 방법은 특정 DBMS에 종속적일 수 있다

javaCopy code
String sql = "SELECT e.* FROM Employee e INNER JOIN Department d ON e.department_id = d.id WHERE d.name = ? AND e.salary > ?";
Query query = entityManager.createNativeQuery(sql, Employee.class);
query.setParameter(1, "IT");
query.setParameter(2, 50000);
List<Employee> result = query.getResultList();

4. QueryDSL

QueryDSL은 타입 세이프한 쿼리를 작성할 수 있는 강력한 도구이다

복잡한 쿼리를 간결하게 작성할 수 있으며, 코드 가독성이 높아진다

javaCopy code
QEmployee employee = QEmployee.employee;
QDepartment department = QDepartment.department;

JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
List<Employee> result = queryFactory
    .selectFrom(employee)
    .join(employee.department, department)
    .where(department.name.eq("IT")
        .and(employee.salary.gt(50000)))
    .fetch();

5. Spring Data JPA Specifications

Spring Data JPA에서는 Specification 인터페이스를 사용하여 동적으로 쿼리를 생성할 수 있다

javaCopy code
public class EmployeeSpecification implements Specification<Employee> {
    private String deptName;
    private int minSalary;

    public EmployeeSpecification(String deptName, int minSalary) {
        this.deptName = deptName;
        this.minSalary = minSalary;
    }

    @Override
    public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        Join<Employee, Department> department = root.join("department");
        return cb.and(
            cb.equal(department.get("name"), deptName),
            cb.greaterThan(root.get("salary"), minSalary)
        );
    }
}

// 사용 예시
Specification<Employee> spec = new EmployeeSpecification("IT", 50000);
List<Employee> employees = employeeRepository.findAll(spec);

결론

복잡한 쿼리를 구현할 때는 JPQL, Criteria API, Native Query, QueryDSL, Spring Data JPA Specifications 등의 방법을 사용할 수 있다

각 방법의 장단점을 고려하여 상황에 맞게 선택하는 것이 중요하다

예를 들어, 동적인 쿼리가 필요한 경우에는 Criteria API나 QueryDSL이 유리할 수 있으며, 복잡한 조인이나 서브쿼리가 필요한 경우에는 Native Query를 사용할 수도 있다

Spring Data JPA를 사용한다면, Specifications을 활용하여 더 깔끔하게 구현할 수도 있다

'Developing > TIL(Develop)' 카테고리의 다른 글

Java 접근제어자  (0) 2024.05.15
Java에서 동일성과 동등성의 차이  (1) 2024.05.15
Spring mvc 패턴  (0) 2024.05.14
Spring JPA 상속 관계  (0) 2024.05.10
Spring Transactional  (0) 2024.05.09