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을 활용하여 더 깔끔하게 구현할 수도 있다
'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 |