[김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술] 스프링 DB 접근 기술 - '스프링 데이터 JPA' 수강
This commit is contained in:
@@ -32,4 +32,5 @@
|
|||||||
- [순수 JDBC](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture19.md)
|
- [순수 JDBC](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture19.md)
|
||||||
- [스프링 통합 테스트](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture20.md)
|
- [스프링 통합 테스트](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture20.md)
|
||||||
- [스프링 JdbcTemplate](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture21.md)
|
- [스프링 JdbcTemplate](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture21.md)
|
||||||
- [JPA](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture22.md)
|
- [JPA](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture22.md)
|
||||||
|
- [스프링 데이터 JPA](https://github.com/banjjoknim/TIL/blob/master/SpringBoot-Introduction/Lectures/Lecture23.md)
|
||||||
82
SpringBoot-Introduction/Lectures/Lecture23.md
Normal file
82
SpringBoot-Introduction/Lectures/Lecture23.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# 스프링 데이터 JPA
|
||||||
|
- `스프링 부트`와 `JPA`만 사용해도 개발 생산성이 정말 많이 증가하고, 개발해야할 코드도 확연히 줄어든다.
|
||||||
|
-여기에 `스프링 데이터 JPA`를 사용하면 기존의 한계를 넘어 마치 마법처럼, 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있다.
|
||||||
|
- 그리고 반복 개발해온 기본 CRUD 기능도 스프링 데이터 JPA가 모두 제공합니다.
|
||||||
|
- 스프링 부트와 JPA라는 기반 위에, 스프링 데이터 JPA라는 환상적인 프레임워크를 더하면 지금까지 조금이라도 단순하고 반복이라 생각했던 개발 코드들이 확연하게 줄어든다.
|
||||||
|
- 따라서 개발자는 핵심 비즈니스 로직을 개발하는데, 집중할 수 있다.
|
||||||
|
- 실무에서 관계형 데이터베이스를 사용한다면 스프링 데이터 JPA는 이제 선택이 아니라 필수이다.
|
||||||
|
|
||||||
|
>**주의**
|
||||||
|
>
|
||||||
|
>스프링 데이터 JPA는 JPA를 편리하게 사용하도록 도와주는 기술이다. 따라서 JPA를 먼저 학습한 후에 스프링 데이터 JPA를 학습해야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SpringDataJpaRepository 인터페이스 생성
|
||||||
|
```java
|
||||||
|
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Optional<Member> findByName(String name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `org.springframework.data.jpa.repository.JpaRepository`를 상속받는다.
|
||||||
|
- 인터페이스는 인터페이스를 `상속(extends)` 받는다(`구현(implements)`-말고).
|
||||||
|
- `JpaRepository<Entity, ID>`의 제네릭 타입은 `Entity`와 `ID`로 지정해야 하며, 각각 `Entity`가 선언된 클래스 타입과 해당 클래스의 `PK` 타입을 지정한다.
|
||||||
|
- 인터페이스는 다중 상속이 된다.
|
||||||
|
- `스프링 데이터 JPA`는 `JpaRepository<Entity, ID>`를 상속받는 인터페이스의 구현체를 `프록시`라는 기능을 이용해서 자동으로 만들어 스프링 빈에 자동으로 등록해준다. 우리는 그걸 그냥 가져다가 쓰는 것이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 스프링 데이터 JPA 회원 리포지토리를 사용하도록 스프링 설정 변경
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
public class SpringConfig {
|
||||||
|
|
||||||
|
private final MemberRepository memberRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public SpringConfig(MemberRepository memberRepository) {
|
||||||
|
this.memberRepository = memberRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MemberService memberService() {
|
||||||
|
return new MemberService(memberRepository);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 위의 `SpringConfig` 생성자에 `MemberRepository`는 다음과 같이 주입된다.
|
||||||
|
- 스프링 컨테이너에서 `MemberRepository`를 찾는다. 이때 `MemberRepository`는 `스프링 데이터 JPA`가 만들고 빈으로 등록해줬던 구현체가(를) 주입된다(주입 받을 수 있다).
|
||||||
|
- `스프링 데이터 JPA`는 `JPA`의 기술을 그대로 가져다 쓰기 때문에 로그가 동일하게 나온다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 스프링 데이터 JPA 제공 클래스
|
||||||
|

|
||||||
|
|
||||||
|
- 기본적으로 `JpaRepository` 인터페이스에서 공통적인 메서드를 제공해준다.
|
||||||
|
- 하지만 예를 들어, 이름으로 찾는다던지 이메일로 찾는다던지 공통적이지 않은 경우 메서드를 정의해줘야 한다.
|
||||||
|
- ex. 메서드명이 `findByName`일 경우, `스프링 데이터 JPA`가 규칙에 따라 되어있는 `select m from Member m where m.name = ?`라는 `JPQL` 쿼리를 짜준다.
|
||||||
|
- 이와 같이 인터페이스 이름만으로 개발을 끝낼 수 있다.
|
||||||
|
- 메서드명과 반환타입, 파라미터 등을 `리플렉션` 기술로 읽어들여서 쿼리로 풀어낸다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 스프링 데이터 JPA 제공 기능
|
||||||
|
- 인터페이스를 통한 기본적인 `CRUD` 기능 제공
|
||||||
|
- `findByName()` , `findByEmail()` 처럼 `메서드 이름 만으로 조회 기능` 제공
|
||||||
|
- `페이징 기능` 자동 제공
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참고
|
||||||
|
- 실무에서는 `JPA`와 `스프링 데이터 JPA`를 기본으로 사용하고, `복잡한 동적 쿼리`는 `Querydsl`이라는 라이브러리를 사용하면 된다.
|
||||||
|
- `Querydsl`을 사용하면 쿼리도 자바 코드로 안전하게 작성할 수 있고, 동적
|
||||||
|
쿼리도 편리하게 작성할 수 있다.
|
||||||
|
- 이 조합으로 해결하기 어려운 쿼리는 `JPA`가 제공하는 `네이티브 쿼리(직접 쿼리를 짜는 것)`를 사용하거나, 앞서 학습한 스프링 `JdbcTemplate`를 사용하면 된다.
|
||||||
|
|
||||||
|
---
|
||||||
BIN
SpringBoot-Introduction/Lectures/images/스프링 데이터 JPA 제공 클래스.PNG
Normal file
BIN
SpringBoot-Introduction/Lectures/images/스프링 데이터 JPA 제공 클래스.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
@@ -1,34 +1,31 @@
|
|||||||
package hello.springintroduction;
|
package hello.springintroduction;
|
||||||
|
|
||||||
import hello.springintroduction.repository.JpaMemberRepository;
|
|
||||||
import hello.springintroduction.repository.MemberRepository;
|
import hello.springintroduction.repository.MemberRepository;
|
||||||
import hello.springintroduction.service.MemberService;
|
import hello.springintroduction.service.MemberService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SpringConfig {
|
public class SpringConfig {
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private final MemberRepository memberRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SpringConfig(EntityManager entityManager) {
|
public SpringConfig(MemberRepository memberRepository) {
|
||||||
this.entityManager = entityManager;
|
this.memberRepository = memberRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public MemberService memberService() {
|
public MemberService memberService() {
|
||||||
return new MemberService(memberRepository());
|
return new MemberService(memberRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
// @Bean
|
||||||
public MemberRepository memberRepository() {
|
// public MemberRepository memberRepository() {
|
||||||
// return new MemoryMemberRepository();
|
// return new MemoryMemberRepository();
|
||||||
// return new JdbcMemberRepository(dataSource);
|
// return new JdbcMemberRepository(dataSource);
|
||||||
// return new JdbcTemplateMemberRepository(dataSource);
|
// return new JdbcTemplateMemberRepository(dataSource);
|
||||||
return new JpaMemberRepository(entityManager);
|
// return new JpaMemberRepository(entityManager);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package hello.springintroduction.repository;
|
||||||
|
|
||||||
|
import hello.springintroduction.domain.Member;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Optional<Member> findByName(String name);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user