JPA 사용할 때 QueryMethod가 많은 해택을 받는다. 레파지토리에 네이밍베이스로 선언만 하면 Query를 불러올수있다. 하지만 먼저 QueryMethod가 어떻게 만들어 지고 작동하는지 알아야한다.
✅ 먼저 UserRepository에 메서드를 만들고
public interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name); //이름을 통해 유저 가져오는 메서드.
}
✅ Test 해보자
@Test
void select() {
System.out.println(userRepository.findByName("martin"));
}
😈 에러가 나는 것은 당연하다 검색한 martin은 2명이기 때문이다.
✅ 리스트 타입으로 바꾸고 해보자.
List<User> findByName(String name); //이름을 통해 유저 가져오는 메서드.
✅ 잘나왔다.
[User(id=1, name=martin, email=martin@fast.com, createdAt=2022-02-04T00:58:41.588, updatedAt=2022-02-04T00:58:41.588),
User(id=5, name=martin, email=james@another.com, createdAt=2022-02-04T00:58:41.603, updatedAt=2022-02-04T00:58:41.603)]
🤔✅👉😎🤚😮
🤚 JpaRepository에서, 즉 쿼리메서드에서는 리턴타입을 고정해야하는것이 아니라 리턴이 1개 or N개에 따라 자동으로 리턴타입을을 제공해준다. 어떤 타입들을 제공하는지 살펴보자.
😮 편리하게 제공하는 장점도 있지만 런타임(실행)할 때 오류가 날수 있으니 정확하게 지정해주는것이 좋다.
JPA에서는 가독성 있는 프로그래밍을 지향해 어떤이름으로 해도 함수를 지정해도된다.
😈 하지만 엔티티에 타입이 명시되어 있으면 findUserByName getUsersByID 같은 접두사 앞에 User라는 명시는 필요없다.
😈 또한 findByByName 이라고 쳐도 Test는 통과하지만 실행중에 오류가 나오니 왠만하면 메서드 이름을 위의 사진대로 하는 것이 좋다. 그리고 꼭 Test 해보는 것을 추천한다.
✅ select문 한번 만들어보자.
User findByEmail(String email);
User getByEmail(String email);
User readByEmail(String email);
User queryByEmail(String email);
User searchByEmail(String email);
User streamByEmail(String email);
User findUserByEmail(String email); // 비추. User는 이미 명시되어있다.
User findSomethingByEmail(String email); // 이렇게 해도 되지만, 비추. 명시적으로 하자
@Test
void select() {
System.out.println(userRepository.findByName("martin"));
System.out.println("findByEmail : " + userRepository.findByEmail("martin@fast.com"));
System.out.println("getByEmail : " + userRepository.getByEmail("martin@fast.com"));
System.out.println("readByEmail : " + userRepository.readByEmail("martin@fast.com"));
System.out.println("queryByEmail : " + userRepository.queryByEmail("martin@fast.com"));
System.out.println("searchByEmail : " + userRepository.searchByEmail("martin@fast.com"));
System.out.println("streamByEmail : " + userRepository.streamByEmail("martin@fast.com"));
System.out.println("findUserByEmail : " + userRepository.findUserByEmail("martin@fast.com"));
System.out.println("findSomethingByEmail : " + userRepository.findSomethingByEmail("martin@fast.com"));
}
결과를 보면 함수이름은 달라도 쿼리가 같다.
✅ 조금 더 실습해 보자. First,Top을 사용해보자. 그리고 Last도 한번 실행해보자.
UserRepository
List<User> findFirst2ByName(String name);
List<User> findTop2ByName(String name);
List<User> findLast1ByName(String name);
UserRepositoryTest
System.out.println("findTop2ByName : " + userRepository.findTop2ByName("martin"));
System.out.println("findFirst2ByName : " + userRepository.findFirst2ByName("martin"));
System.out.println("findLast1ByName : " + userRepository.findLast1ByName("martin"));
👉 martin을 조건으로 Limit를 걸어서 2명을 출력한다. 굿굿!!
🤚 하지만 findLast1ByName은 정상적으로 작동했을까?
👉 Test는 통과하였지만 정상 작동은 아니다. Last 라는 Keyword는 JPA에서 감지하지 못하기 때문이다. 그래서 일반 select쿼리를 뱉어냈다.
🤚 참고사항으로... Last를 뽑으려면 OrderBy를 사용하여 역순정렬하고 first1을 사용하면 된다.
✅ 실습해보자
👉 findByEmailAndName
// AND
List<User> findByEmailAndName(String email, String name);
// OR
List<User> findByEmailOrName(String email, String name);
// After('>',~보다 큰것), Before('<',~보다 작은 것)
List<User> findByCreatedAtAfter(LocalDateTime yesterday);
List<User> findByIdAfter(Long id);
// GreaterThan == (After Before와 같지만, 좀 더 범용적으로 사용 가능 모든 숫자 값 날짜 값 사용가능하다.)
List<User> findByCreatedAtGreaterThan(LocalDateTime yesterday);
// GreaterThanEqual('이상','>=') (참고로 Before,After는 초과,미만 만 가능하다.)
List<User> findByCreatedAtGreaterThanEqual(LocalDateTime yesterday);
// Between (~와 ~사이) (양끝의 값을 포함한다!!!!)
List<User> findByCreatedAtBetween(LocalDateTime yesterday, LocalDateTime tomorrow);
List<User> findByIdBetween(Long id1, Long id2);
// (Between을 풀어서 쓴 것) GreaterThanEqual And LessThanEqual (~이상 그리고 ~이하)
List<User> findByIdGreaterThanEqualAndIdLessThanEqual(Long id1, Long id2);
// IsNotNull (빈 값이 아닌 것 찾기) (IsNull은 빈 값 찾기)
List<User> findByIdIsNotNull();
// In ('문자'를 가지고있는 스키마 찾기) (or조건과 비슷하다)
List<User> findByNameIn(List<String> names);
// StartingWith ('?' 으로 시작하는 문자를 가지고있는 스키마 찾기)
List<User> findByNameStartingWith(String name);
// EndingWith ('?' 으로 끝나는 문자를 가지고있는 스키마 찾기)
List<User> findByNameEndingWith(String name);
// Contains ('?' 글자를 포함하는 문자를 가지고있는 스키마 찾기)
List<User> findByNameContains(String name);
// Like ( 위 3개 쿼리를 복합적으로 사용 , %A [A로 끝] , A% [A로 시작] , %A% [A포함]
List<User> findByNameLike(String name);
// Is ,Equals (파라미터와 일치하는 쿼리)(코드 가독성을 높혀준다.)
Set<User> findUserByNameIs(String name);
Set<User> findUserByNameEquals(String name);
System.out.println("findByEmailAndName : " + userRepository.findByEmailAndName("martin@fast.com", "martin"));
System.out.println("findByEmailOrName : " + userRepository.findByEmailOrName("martin@fast.com", "dennis"));
System.out.println("findByCreatedAtAfter : " + userRepository.findByCreatedAtAfter(LocalDateTime.now().minusDays(1L)));
System.out.println("findByIdAfter : " + userRepository.findByIdAfter(4L));
System.out.println("findByCreatedAtGreaterThan : " + userRepository.findByCreatedAtGreaterThan(LocalDateTime.now().minusDays(1L)));
System.out.println("findByCreatedAtGreaterThanEqual : " + userRepository.findByCreatedAtGreaterThanEqual(LocalDateTime.now().minusDays(1L)));
System.out.println("findByCreatedAtBetween : " + userRepository.findByCreatedAtBetween(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusDays(1L)));
System.out.println("findByIdBetween : " + userRepository.findByIdBetween(1L, 3L));
System.out.println("findByIdGreaterThanEqualAndIdLessThanEqual : " + userRepository.findByIdGreaterThanEqualAndIdLessThanEqual(1L, 3L));
System.out.println("findByIdIsNotNull : " + userRepository.findByIdIsNotNull());
System.out.println("findByNameIn : " + userRepository.findByNameIn(Lists.newArrayList("martin", "dennis")));
System.out.println("findByNameStartingWith : " + userRepository.findByNameStartingWith("mar"));
System.out.println("findByNameEndingWith : " + userRepository.findByNameEndingWith("tin"));
System.out.println("findByNameContains : " + userRepository.findByNameContains("art"));
System.out.println("findByNameLike : " + userRepository.findByNameLike("%" + "art" + "%"));