JPA를 더 편리하게 만들어주는 라이브러리인 스프링 데이터 JPA를 간단하게 배우는 회차이다.
JPA를 배우는 것만으로도 백엔드 코딩이 매우 편리해지는데, 스프링 데이터 JPA를 배우면 "이렇게까지 편해진다고?" 싶은 수준으로 좋다고 한다.
그러나 JPA를 제대로 배우지 않은 상태에서 스프링 JPA를 배우는 것은 금물이다!
요즘 JPA가 정말 중요하고, 필수로 배워야 한다고 해도 무방할 정도로 능률을 많이 올려주는 기술이므로
JPA를 먼저 제대로 배운 다음 스프링 JPA까지 배우면 좋을 것!
공부할 것이 굉장히 많다.
자바 공부도 틈틈이 더 해야 할 것 같고 (책을 사야 하나?)
일단은 스프링을 탄탄히 공부해야 하고 (시간이 없다면 자바는 스프링을 하면서 부족하다 느껴지는 부분만 취사선택하여 공부해야 할 수도...)
그러면서 SQL도 잊어버리지 않게 훑어야 하고
스프링 못지 않게 굉장히 공부할 게 많은 JPA
그 다음엔 스프링 데이터 JPA까지
정말 공부할 것이 많다.
강사님께서
할 거 정말 많죠? 그래서 서버 개발자들이 대우도 잘 받고 그러는 겁니다 라고 위로의 말씀을 해주셨다.
이걸 들으니 오기가 생긴다.
공부할 것이 끝없이 많다는 것은 오히려 좋은 일이다! 죽을 때까지 공부해보자
스프링 JPA 동작을 위한 인터페이스 만들기
스프링 데이터 JPA를 사용하면 놀랍게도
구현체 없이 인터페이스만으로 코딩이 끝난다.
그러므로 이번에는 지금까지와 다르게 클래스가 아닌 인터페이스를 만든다.
인터페이스는 다중 상속을 받을 수 있다.
이 인터페이스는
스프링이 제공하는 JpaRepository 인터페이스와
기존에 우리가 만들어둔 MemberRepository 인터페이스를 상속받는다.
JpaRepository의 <> 내에 들어간 것은
이 인터페이스가 관리할 데이터의 타입과 그 데이터의 ID(Primary Key)의 타입이다.
그리고 findByName만 이렇게 적어주면 끝난다.
띠용?
당황하고 있었는데, 강사님께서 내가 궁금해하고 있는 부분을 그대로 읊어주셨다. "인터페이스만 있고 구현체도 없고 다른 메소드들은 다 어디 갔죠?"
Configuration 설정
그러더니 Configuration 설정으로 넘어가셨다. 일단 테스트를 돌려본 다음에 설명을 해주시기 위해서이다.
완성된 SpringConfig 코드도 인터페이스 못지 않게 특이하다.
이것만 있으면 되고
어노테이션은 이렇게 붙인다.
SpringConfig 생성자가 하나뿐이므로 @Autowired는 생략해도 된다.
이러면 끝이다... 이제 냅다 테스트를 돌린다.
일단 join만 돌려봤다.
잘 된다. 신기하다.
전체 테스트도 잘 된다.
이게 가능한 이유
첫째, 인터페이스만 달랑 만들고 구현체는 안 만들었는데 어떻게 작동이 되는가?
이 친구가 마법을 부려주기 때문이다.
이걸 extends해놓으면 프록시라는 기술...에 의하여
스프링 데이터 JPA가 알아서 구현체를 만들고 그 구현체의 객체를 스프링 빈으로 등록까지 해준다고 한다.
그러고 보니 SpringConfig에도 Service 객체를 빈으로 등록하는 코드만 있을 뿐...
SpringDataJpaMemberRepository 객체를 빈으로 등록하는 코드는 없다...
너무 다 해줘서 아기가 된 기분이다. 자세한 원리는 공부를 더 해보아야 알겠지만 정말 신기하다.
둘째, SpringDataJpaMemberRepository 안에 findByName 단 하나만 만들었는데 어떻게 다른 메소드들(save, findById, findAll)이 작동을 하는가?
이것 또한 이 친구가 마법을 부려주기 때문이다.
아래 스프링 공식 문서의 JpaRepository 항목을 보면,(강의자료에도 간단히 나와있다)
데이터베이스와 관련하여
내가 상상할 수 있는 모든 기본 메소드들이 다 마련되어있다.
삽입, 삭제, Primary Key를 이용하여 찾아오기, 모두 찾아오기...
우리가 만들어서 사용하던 findById와 findAll도 있다.
이 순간의 놀라움을 위하여 강사님께서 애초에 메소드 이름을 이것과 동일하게 맞추어두신 거라 한다. 빅픽처 실화냐
그러나! Primary Key가 아닌 다른 값을 기준으로 작동하는 메소드는 마련되어있지 않다. 이렇게 각 상황에 특화된 컬럼들은 너무나 다양하기 때문에 여기다 다 마련해놓을 수 없다.
그래서
여기에다가는 findByName만 적으면 되었던 것이다.
다른 동작들은 다 기본적인 삽입 및 찾아오기이므로 따로 써줄 필요가 없고,
우리가 맘대로 집어넣은 컬럼인 name이 Primary Key가 아니므로
이놈은 직접 적어준 것이다.
셋째, findByName의 내용을 전혀 채우지 않고 이름과 리턴 타입, 매개변수만 지정해주었는데 어떻게 작동하는 것인가?
스프링 데이터 JPA가 이 인터페이스를 기반으로 구현체를 만들 때,
내부에 들어있는 메소드들의 구현도 당연히 하게 되는데,
이때 그 구현 내용을
인터페이스 상의 메소드의 이름과 리턴 타입과 매개변수만 보고 알아서 정한다고 한다.
이게 말이 되나? 스프링 데이터 JPA는 전설이다.
대충 다음과 같다.
Optional<Member> findByName(String name);
우리가 만든 인터페이스에 이런 내용이 적혀있다.
먼저 이름을 보자.
find 뒤에, By 뒤에,
Name이 있으므로
스프링 데이터 JPA는
"아하 name이라는 컬럼의 값을 기준으로 데이터를 찾는 메소드구나!"
라는 사실을 딱 알아낸다.
그리고 JpaRepository<Member, Long>을 적어준 덕에 찾아올 데이터의 클래스가 Member라는 것을 알고 있다.
따라서 다음과 같은 JPQL을 자동으로 만들어내어 사용한다.
"select m from Member where m.name = ?"
그리고 매개변수로 String name 이 주어지므로
"그 기준은 이 문자열 변수 name이구나!"
또한 알아낸다.
그리고 리턴 타입에 맞게 값을 돌려준다.
만약 메소드 이름이 findByAge 라면 age라는 컬럼의 값을 기준으로 데이터를 찾을 것이다.
and와 or 같은 걸로 응용을 할 수도 있다.
예를 들어 메소드 이름이 findByNameAndAge 라면 name과 age라는 컬럼 두 개의 값을 기준으로 데이터를 찾을 것이다.
우리가 대충 이름만 던져준 요소들을 가져다 리플렉션으로 조사한 다음, 그 정보를 풀어내어 이렇게 편리한 도구를 만들어주고 있다.
페이징 기능이라는 것도 자동으로 제공한다는데 이것은 처음 들어본다. 더 공부해보자.
정말 신기하다.
인터페이스 구성요소의 이름만으로도 개발이 된다.
그동안 "이게 되면 대박이다" 싶었던 것들이 다 이미 실현되어있었다.
물론 아주 복잡하거나 특화된 쿼리를 사용하려면 이 기능을 사용하지 않고 직접 짜야 한다. 그러나 자주 쓰는 몇 가지 메소드들을 이렇게 편하게 만들어낼 수 있다는 것만으로도 굉장한 일이다. 많은 경우에 이런 기본적인 것들이 프로젝트의 대부분을 차지하고, 손수 짜야 하는 복잡하거나 특이한 기능은 극히 일부이기 때문이라고 한다.
실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용한다.
복잡한 동적 쿼리는 Querydsl이라는 라이브러리를 사용하면 된다.
JPA를 실무에서 딥하게 사용하시는 분들은 JPA, 스프링 데이터 JPA, Querydsl을 조합하여 사용하신다고 한다.
이 조합으로 해결하기 어려운 경우에는 SQL문을 좀 더 직접 쓰는 방법을 택하면 된다. JPA가 제공하는 네이티브 쿼리를 사용하거나 앞서 학습한 스프링 JdbcTemplate을 사용하는 것이다.
'스프링 공부 > 인프런 김영한 스프링 입문 노트정리' 카테고리의 다른 글
7-2. AOP 적용 (0) | 2022.08.19 |
---|---|
7-1. AOP가 필요한 상황 (0) | 2022.08.19 |
6-5. JPA (0) | 2022.08.01 |
6-4. 스프링 JdbcTemplate (0) | 2022.07.31 |
6-3. 스프링 통합 테스트 (0) | 2022.07.31 |