JPQL개념과 사용법 패턴 정리
이번 글에는 실무에서 제가 자주 사용하는 JPQL에 대해 알아보겠습니다. 소모 비용이 많이 드는 쿼리들은 QueryDSL을 통해 최적화하지만, 확인하거나 간단하게 확인 할 수 있는 부분들은 JPQL을 사용하여 조회하고 있습니다. 그러면 자주 사용하는 JPQL에 대해 정리해 봅시다.
JPQL이란?
JPQL는 Java Persistence Query Language의 약자로, 데이터베이스에 저장된 엔티티를 조회하기 위한 객체지향 쿼리 언어입니다. SQL과 유사하지만 엔티티 객체와 필드를 대상으로 한다는 차이점이 있습니다. 또한 SQL과 유사하게 SELECT, DELETE, UPDATE 등의 기본적인 구문뿐만 아니라 다양한 쿼리 작성도 지원합니다.
JPQL 조회
저는 보통 JPQL로 조회할 때는 쿼리 메서드로 조회를 자주 사용합니다. 복잡하지 않고 단순하게 조회가 필요할때에 대해서 사용하며 제가 자주 사용하는 패턴들을 설명드리겠습니다.
- findBy: 조건과 일치하는 값에 대하여 단일값을 반환합니다.
// where Id = :1L
Post findPost = postRepository.findById(1L);
// where Title = :title
Post findPostTitle = postRepository.findByTitle(title);
- findAllBy: 조건과 일치하는 값에 대하여 여러값을 반환합니다.
// where x
List<Post> findPostList = postRepository.findAll();
// where id in :ids
Post findPostIdsList = postRepository.findAllByIdIn(Ids);
- findTopBy : 조건과 일치하는 값에 대하여 가장 상위의 값을 가져옵니다.
// where first limit 1
Post topPost = postRepository.findTopBy();
// where active = :true Order by Id Desc limit 3
List<Post> findPostIdsList = postRepository.findTop3ByActiveTrueOrderByIdDesc();
- 아래는 자주 사용하게 될 JPQL 네이밍 컨벤션 목록입니다.
Distinct | findDistinctByName | SELECT distinct WHERE name = :name |
And | findByActiveAndDelete | active = :boolean AND delete = :boolean |
Or | findByNameOrName | name = :name OR name = :name |
Between | findByCreateDateBetween | createDate between :date and :date |
LessThan | findByIdLessThan | Id < :id |
LessThanEqual | findByIdLessThanEqual | Id <= :id |
GreaterThan | findByAgeGreaterThan | Id > :id |
GreaterThanEqual | findByAgeGreaterThanEqual | Id >= :id |
After | findByCreateDateAfter | createDate > :date |
Before | findByCreateDateBefore | createDate < :date |
IsNull, Null | findByName(Is)Null | name is null |
IsNotNull, NotNull | findByName(Is)NotNull | name is not null |
Like | findByNameLike | name like :name |
NotLike | findByNameNotLike | name not like :name |
Containing | findByNameContaining | name like % :name % |
OrderBy | findByIdOrderByCreateDateDesc | id = :id ORDER BY createDate DESC |
Not | findByNameNot | name <> :name |
In | findByIdIn | Id in :ids |
NotIn | findByIdNotIn | Id not in :ids |
True | findByActiveTrue | active = true |
False | findByActiveFalse | active = false |
JPQL 저장, 수정, 삭제
저희는 보통 등록, 수정, 삭제 작업을 거칠 때 쿼리 메소드를 이용합니다. 이때 기본 제공된 쿼리 메소드로 수많은 데이터를 처리하면 어떻게 될까요? 처리가 이루어지는 행의 수만큼 반복되어 쿼리가 발생하게 됩니다.
//단건 저장or수정
postRepository.save(post);
//여러건 수정 -> 해당 행의 개수만큼 여러번 UPDATE 쿼리가 나가게 된다.
postRepository.saveAll(postList);
//단건 삭제
postRepository.delete(post);
//여러건 삭제 -> 해당 행의 개수만큼 여러번 DELETE 쿼리가 나가게 된다.
postRepository.deleteAll(post);
JPQL Modifying
위의 문제점을 해결하려면 JPQL를 통해 한 번의 연산으로 여러 엔티티의 상태를 변경할 수 있는 벌크 연산을 진행할 수 있습니다. 영속성 컨텍스트를 거치지 않고 DB에 바로 접근하여 쿼리를 날리게 됩니다.
@Transactional
@Modifying
@Query("UPDATE Post p SET p.active = false WHERE p.id In :ids")
void updateByPostActiveFalse(@Param("ids") List<Long> postIds);
@Transactional
@Modifying
@Query("DELETE FROM User u WHERE u.active = false")
void deleteByUserActiveFalse();
JPQL Modifying의 영속성 문제 해결 방법
JPQL을 통한 벌크 연산은 영속성 컨텍스트를 거치지 않고 DB에 바로 저장이 되며 잘못 사용하게 될 경우 JPA의 엔티티 상태간의 불일치가 발생할 수 있습니다. 이를 해결하기 위해 clearAutomatically를 사용할 수 있습니다. 이는 다음과 같이 사용됩니다.
@Transactional
@Modifying(clearAutomatically = true)
@Query("UPDATE User u SET u.active = true WHERE u.id In :ids)
void updateByUserActiveTrue(@Param("ids") List<Long> userIds);
clearAutomatically를 true로 설정하게 되면 저장하고 나서 영속성 컨텍스트를 초기화하여 현재의 영속성과 일치 시켜주어 상태간의 불일치 문제를 해결해줍니다.
JPQL은 자주 사용하고 데이터베이스 상의 엔티티를 객체지향적으로 다루기 위한 쿼리 언어입니다. 이 글에서는 JPQL의 기본 개념부터 조회, 저장, 수정, 삭제에 이르기까지 실무에서 자주 사용하는 패턴과 벌크 연산에 대해 알아보았습니다. 실무에서 JPQL을 활용함으로써, 복잡하고 소모 비용이 많이 드는 쿼리들은 QueryDSL로 최적화하고, 간단한 조회는 JPQL로 처리하여 전체 애플리케이션의 성능과 유지보수성을 향상시킬 수 있습니다. JPQL은 JPA를 사용하는 Java 개발자에게 필수적인 도구이며, 이를 통해 데이터 관리의 복잡성을 줄이고, 개발 프로세스를 더욱 효율적으로 만들 수 있습니다.
'Spring' 카테고리의 다른 글
[JPA] JPA Pagination 처리 방법 (Pageable, Page, Slice) (0) | 2024.02.28 |
---|---|
[JPA] Batch Insert로 대량의 데이터 처리하기 (0) | 2024.02.27 |
[JPA] QueryDSL의 페이징 카테시안 곱 문제 해결 방법 (1:N Pagination) (0) | 2024.02.16 |
[JPA] QueryDSL에서 JPA N+1 문제 해결하기 (0) | 2024.02.13 |
[JPA] JPA의 연관관계 예제 정리 (1) | 2024.02.05 |