Spring Boot - JPA Query Method

김명식·2023년 5월 3일
0

Spring Boot

목록 보기
4/11
post-thumbnail

Query Method

Query Method는 JPA 에서 제공하는 핵심 기능 중 하나이다.

Repository Interface에 간단한 네이밍 룰을 이용,
별도의 쿼리 작성 없이 데이터베이스와 소통할 수 있게 해준다.

  QueryMethod Naming Rule - 
  1. 메서드 이름은 "findBy" 로 시작.
  
  2. findBy 다음에는 검색 조건으로 사용할 Entity field 이름을 적는다.
     이 때, 필드 이름은 대소문자를 구분한다.
  
  3. 필드 이름 다음에는 검색 조건 연산자를 적는다.
     연산자는 다음과 같이 사용할 수 있다.
 		
  		Equals: "findBy[Field]Equals"
		
  		NotEquals: "findBy[Field]Not"
	
  		LessThan: "findBy[Field]LessThan"
	
  		LessThanEquals: "findBy[Field]LessThanEquals"
	
  		GreaterThan: "findBy[Field]GreaterThan"
	
  		GreaterThanEquals: "findBy[Field]GreaterThanEquals"
	
  		Like: "findBy[Field]Like"
	
  		NotLike: "findBy[Field]NotLike"
	
  		StartingWith: "findBy[Field]StartingWith"
	
  		EndingWith: "findBy[Field]EndingWith"
	
  		Contains: "findBy[Field]Containing"
	
  		NotContains: "findBy[Field]NotContaining"
  
  4. 조건이 여러개인 경우에는 "And"를 사용하여 연결한다.
  		
  		findBy[firstField]And[secondField]
  
  5. 조건이 여러개이지만, Or 조건으로 연결하고 싶은 경우에는 "Or"를 사용하여 연결한다.
  		findBy[sirstField]Or[secondField]
  

위 QueryMethod의 명칭을 보면 알 수 있듯 각 메서드의 역할을 글자만으로 이해할 수 있어 가독성이 좋다.
이렇게 작성된 메서드는 JPA에서 자동으로 해당 필드를 이용한 쿼리를 생성하게 된다.
또한 메서드의 파라미터에 값을 전달하면 이 값들이 쿼리의 조건으로 적용 된다.


QueryMethod를 직접 사용해서 테스트코드를 만들어보자.
간단히 [ 상품명 또는 상품가격을 통해 조회 ] 하는 Query Method를 작성 해보겠다.

Entity - 

@Entity
@Table(name="item")
@Getter
@Setter
@ToString
public class Item {
        
		@Id
		@GeneratedValue(strategy = GenerationType.AUTO)
		private Long id;
		
		private String itemName; // 상품명
		private int price; // 가격

}
Repository - 

public interface ItemRepository extends JPARepository<Item, Long> {

		// 이름이 같거나 가격이 적다면 
		List<Item> findByItemNameOrPriceLessThan(String itemName, Integer price);

}
TestCode - 

@SpringBootTest
class ItemRepositoryTest {

	// 의존성 주입
	@Autowired
	ItemRepository itemRepository;

	@Test
	@DisplayName("상품명 OR 가격 조회 테스트") 
	public void QueryMethodTest() {

		// 테스트용
		Item item = new Item();
		item.setItemName("테스트아이템");
		item.setPrice(100);

		// DB에 저장
		itemRepository.save(item);
		
		// 조회
		List<Item> itemList = itemRepository.findByItemNameOrPriceLessThan("테스트아이템", 1000);

		for (Item item : itemList) {

			System.out.println(item.toString());

		}

	}

}

테스트 코드를 실행하면
정상적으로 값을 직접 setter로 바인딩한 Item [ItemName = "테스트아이템", price = 100] 이 출력된다.

QueryMethod의 조건을 Or로 하고 price 조건을 LessThan으로 했기 때문에

[ 정상 List ]
ItemName = "TestItem", [ --- false ]
price = 100 [ --- true ]

[ 정상 List ]
ItemName = "테스트아이템", [ --- true ]
price = 100000 [ --- false ]

[ 빈 리스트 ]
ItemName = "TestItem", [ --- false ]
price = 100000 [ --- false ]

위와 같은 결과를 확인할 수 있다.


QueryMethod는 앞서 말한바와 같이 메서드 명만으로 어떤 동작을 하는지 예측이 가능하므로
가독성이 있다는 말을 했지만, 사실 이건 반은 맞고 반을 틀린 말이다.

그 이유는, QueryMethod의 조건이 많을 경우 오히려 메서드명이 너무 길어져 읽기 불편하기 때문이다.


쿼리를 자주 접한 개발자라면 다음과 같은 쿼리가 무슨 동작을 하는지 빨리 캐치할 수 있을 것이다.
select *
from Item
where itemName = '핫식스'
	and price between 100 and 300
	and count > 100

- 개발자 : 상품명이 '핫식스'고 가격은 100사이에서 300사이, 개수가 100개 이상인 제품을 찾는 쿼리구나.

매우 간단한 이 쿼리를 QueryMethod로 나타내면

List<Item> findByItemNameAndPriceBetweenAndCountGreaterThan();

- 개발자 : 상품명을 찾고... 가격이 .. A랑 B 사이고 .. 개수가 .. Greater .. 보다 많은 것을 찾는 쿼리..?

이런식으로 알아보기 힘들어진다.
물론 위 쿼리는 and가 2개밖에 없으므로 쿼리가 능한 개발자라면 바로 이해하겠지만 (아직 난 아니다)
조금이라도 더 연산이 많아진다면 저 긴 문장을 해석할 시간에 차라리 MyBatis를 사용할것이다.

그렇기 때문에 꼭 JPA를 쓴다고 Database와 소통할 때 QueryMethod가 만능인게 아니다.

그렇다면 JPA는 긴 조건을 가진 쿼리를 다뤄야할때 불리한가?


전혀 아니다 !


QueryMethod에 한해서는 불리한게 맞지만,
JPA는 QueryMethod 이외에도 다양한 Database와 소통하는 방식을 가지고 있다.
그 중 대표적인게 바로 QueryDSL , @Query 어노테이션 이다.

나 또한 실무에서는 QueryMethod 보다 위 두개, 그 중 특히나 QueryDSL 을 많이 사용했다.

위 두 방법은 다음 포스팅에서 각각 기술하겠다.

profile
BackEnd & AWS Developer

0개의 댓글