JPA 정적쿼리, 동적쿼리(feat. JpaSpecificationExecutor)
by 볼빵빵오춘기정적쿼리(JPA문법 사용)
- 정적 쿼리는 조건이 고정된 쿼리로, 쿼리 메서드를 통해 정의된다.
- 정적쿼리 사용 방법은 단순하고 직관적이지만, 조건이 고정되어 있어 동적인 요구사항을 처리하기 어렵다.
- 모든 조합의 메서드를 만들어야 하므로, 조건이 많아지면 관리가 복잡해진다.
public interface ProtectRepository extends JpaRepository<ProtectEntity, Long> {
Page<ProtectEntity> findByKindAndGenderAndDate(String kind, String gender, String date, Pageable pageable);
}
동적쿼리(JpaSpecificationExecutor 사용)
- 동적 쿼리는 조건을 런타임에 결정할 수 있으며, Specification 인터페이스를 사용하여 정의된다.
- 여러 조건을 조합하거나 조건을 선택적으로 적용할 수 있어 유연하다.
- 동적쿼리 사용 방법은 조건이 많고 다양하게 조합되어야 하는 경우에 유리하므로 코드를 재사용할 수 있어 유지보수가 용이하다.
public interface ProtectRepository extends JpaRepository<ProtectEntity, Long>, JpaSpecificationExecutor<ProtectEntity> {
}
정적쿼리, 동적쿼리 장단점
정적쿼리 | 동적쿼리 | |
장점 | - 단순함: 조건이 몇 개 없고, 조합이 많지 않을 때는 직관적으로 작성할 수 있다. - 명시성: 어떤 쿼리가 실행되는지 명확하게 알 수 있다. |
- 유연성: 여러 조건을 동적으로 조합할 수 있다. - 재사용성: 조건을 정의하는 코드의 재사용성이 높다. - 유지보수 용이: 새로운 조건이 추가되더라도 기존 코드를 크게 변경하지 않고 추가할 수 있다. |
단점 | - 유연성 부족: 조건이 많아지면 메서드의 조합이 기하급수적으로 늘어날 수 있다. - 유지보수 어려움: 조건이 추가되거나 변경될 때마다 새로운 메서드를 추가해야 한다. |
- 복잡도: 처음 사용 시 이해하고 설정하는 과정이 조금 더 복잡할 수 있다. - 추상화: 쿼리가 추상화되어 있어, 어떤 SQL이 실행되는지 바로 알기 어려울 수 있다. |
결론 | 조건이 단순하고 고정된 경우, 메서드 명만으로 충분히 표현 가능한 경우에 적합하다. | 조건이 다양하고, 동적으로 조합해야 하는 경우, 그리고 유지보수와 확장성이 중요한 경우에 적합하다. |
JpaSpecificationExecutor
- Spring Data JPA에서 제공하는 인터페이스로, JPA Criteria API를 사용하여 동적 쿼리를 생성할 수 있게 해준다.
- 이 인터페이스를 사용하면 복잡한 검색 조건을 쉽게 정의하고, 동적으로 쿼리를 생성하여 실행할 수 있다.
- 주요 기능으로는 동적쿼리를 생성하고 검색 조건 쿼리를 작성할 때 유연하다.
동적 쿼리 사용방법
엔티티 클래스
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private int age;
// getters and setters
}
리포지토리 인터페이스
JpaSpecificationExecutor 인터페이스를 상속받는 리포지토리를 정의한다.
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
스펙 정의
Specification을 사용하여 동적 쿼리를 정의한다.
public class UserSpecifications {
public static Specification<User> hasFirstName(String firstName) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
return cb.equal(root.get("firstName"), firstName);
};
}
public static Specification<User> hasLastName(String lastName) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
return cb.equal(root.get("lastName"), lastName);
};
}
public static Specification<User> isOlderThan(int age) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
return cb.greaterThan(root.get("age"), age);
};
}
}
서비스 클래스
서비스 클래스에서 JpaSpecificationExecutor를 사용하여 동적 쿼리를 실행한다.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> findUsers(String firstName, String lastName, int age) {
Specification<User> spec = Specification.where(null);
if (firstName != null) {
spec = spec.and(UserSpecifications.hasFirstName(firstName));
}
if (lastName != null) {
spec = spec.and(UserSpecifications.hasLastName(lastName));
}
if (age > 0) {
spec = spec.and(UserSpecifications.isOlderThan(age));
}
return userRepository.findAll(spec);
}
}
정리
- 두 방법을 상황에 맞게 혼용하여 사용해야할 것 같다.
- 조건이 많고 복잡한 경우 JpaSpecificationExecutor를 사용하고, 조건이 단순한 경우 JPA의 정적 쿼리를 사용하면 될 것 같다.
- 프로젝트의 요구사항과 복잡도에 따라 적절한 방법을 선택하면 될 듯 하다.
- 간단하게 동적쿼리를 사용해 보긴 했는데 처음 쓰는거라 그런지 정신은 없다.
'👩🏻💻 About 프로그래밍 > spring' 카테고리의 다른 글
파일 업로드(하나 업로드 vs 여러 개 업로드) (0) | 2024.07.20 |
---|---|
JPA 동적쿼리 사용해보기 (0) | 2024.07.19 |
JPA 반환타입 (0) | 2024.07.18 |
Spring Data Jpa 쿼리 메소드, 네이밍 규칙, 네이티브 쿼리 (0) | 2024.07.15 |
JPA란? (feat. ORM) (0) | 2024.07.15 |
블로그의 정보
Hello 춘기's world
볼빵빵오춘기