✔ JPA
• CRUD + 쿼리
: 단순히 CRUD 만 하는 것이 아니고, 쿼리에 대한 부분도 어느정도 지원이 된다.
• 동일한 인터페이스
: CRUD Repository (저장소)
• 페이징 처리
• 메서드 이름으로 쿼리 생성
• 스프링 MVC 에서 id 값만 넘겨도 도메인 클래스로 바인딩
✔ JPA 의 기능
➕ Spring Data JPA
public interface MemberRepository extends JpaRepository<Member, Long> {
// 실제 아무것도 없음
}
위의 MemberRepository가 Spring Data가 제공하는 JpaRepository만 상속받으면
• <S extends T> S save(S entity)
• void delete(ID id)
• Optional<T> findById(ID id)
• Iterable<T> findAll
• long count()
• 기타 등등...
이것들이 다 기본으로 제공된다.
➕ 메서드 이름으로 쿼리 생성
public interface MemberRepository extends JpaRepository<Member, Long> {
List<User> findByEmailAndName(String email, String name);
}
이름을 findByEmailAndName으로 하고 파라미터로 email, name 을 넘기면
// [생성된 JPQL]
select m from Member m
where m.email = ?1
and m.name = ?2
이름만으로 분석을 해서 자동으로 위의 JPQL이 생성된다.
➕ @Query (JPA 네이티브 쿼리)
// 인터페이스에 쿼리 작성 기능
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
// JPA 네이티브 쿼리 지원
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?0", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
✔ JPA 장점
• 코딩량이 줄어듦
• 도메인 클래스를 중요하게 다룸 (엔티티를 사용하기 때문에)
• 비지니스 로직 이해 쉬움
• SQL을 작성할 시간에 더 많은 테스트 케이스 작성 가능
- build.gradle 에 추가
// JPA, 스프링 데이터 JPA 추가
implementation 'org.springframework.boot:spring-boot-starter-data-jpa';
- application.properties 에 추가
#JPA log
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
- 스프링 데이터 JPA
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
- 스프링 데이터 JPA는 메서드 이름을 분석해서 필요한 JPQL을 만들고 실행해 준다.
(JPQL은 JPA가 SQL로 번역해서 실행한다.)
📌 다음과 같은 규칙을 따라야 한다.
• 조회 : find...By, read...By, query...By, get...By
예) findHelloBy 처럼 ...에 식별하기 위한 내용(설명)이 들어가도 된다.
• COUNT : count...By 반환타입 long
• EXSITS : exists...By 반환타입 boolean
• 삭제 : delete...By, remove...By 반환타입 long
• DISTINCT : findDistinct, findMemberDistinctBy
• LIMIT : findFirst3, findFirst, findTop, findTop3
📌 스프링 데이터 JPA도 Example이라는 기능으로 약간의 동적 쿼리를 지원하지만, 실무에서 사용하기는 기능이 빈약하다. 실무에서 JPQL 동적 쿼리는 Querydsl에서 동적 쿼리로 깔끔하게 해결할 수 있다.
• findAll()
- 코드에는 보이지 않지만, JpaRepository 공통 인터페이스가 제공하는 기능이다.
- 모든 Item을 조회한다.
- select i from Item i 가 실행된다.
• findByItemNameLike()
- 이름 조건만 검색했을 때 사용하는 쿼리 메서드이다.
- select i from Item i where i.name like ? 가 실행된다.
• findByPriceLessThanEqual()
- 가격 조건만 검색했을 때 사용하는 쿼리 메서드이다.
- select i from Item i where i.price <= ? 가 실행된다.
• findByItemNameLikeAndPriceLessThanEqual()
- 가격 조건만 검색했을 때 사용하는 쿼리 메서드이다.
- select i from Item i where i.price <= ? 가 실행된다.
• findItems()
- 메서드 이름으로 쿼리를 실행하는 기능은 다음과 같은 단점이 있다.
① 조건이 많으면 메서드 이름이 너무 길어진다.
② 조인 같은 복잡한 조건을 사용할 수 없다.
: 메서드 이름으로 쿼리를 실행하는 기능은 유용하지만, 복잡해지면 직접 JPQL 쿼리를 작성하는 것이 좋다.
- 쿼리를 직접 실행하려면 @Query 어노테이션을 사용하면 된다.
- 메서드 이름으로 쿼리를 실행할 때는 파라미터를 순서대로 입력하면 되지만, 쿼리를 직접 실행할 때는 파라미터를 명시적으로 바인딩 해야 한다.
- 파라미터 바인딩은 @Param("itemName") 어노테이션을 사용하고, 어노테이션의 값에 파라미터 이름을 주면 된다.
- 예제
package hello.itemservice.domain;
import lombok.Builder;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
public class Item {
// pk
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "item_name", length = 10)
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
◽ @Entity : JPA가 사용하는 객체라는 뜻이다. 이 에노테이션이 있어야 JPA 가 인식할 수 있다. 이렇게 @Entity 가 붙은 객체를 JPA에서는 엔티티라고 한다.
◽ @ Id : 테이블의 PK와 해당 필드를 매핑한다.
◽ @GenerateValue(strategy = GenerationType.IDENTITY) : PK 생성 값을 데이터베이스에서 생성하는 IDENTITY 방식을 사용한다. 예) MySQL auto increment
◽ @Column : 객체의 필드를 테이블의 컬럼과 매핑한다.
- name = "item_name" : 객체는 itemName 이지만 테이블의 컬럼은 item_name 이므로 이렇게 매핑했다.
- length = 10 (varchar 10) :JPA의 매핑 정보로 DDL도 생성할 수 있는데, 그 때 컬럼의 길이 값으로 활용된다.
- @Column 을 생략할 경우 필드의 이름을 테이블 컬럼 이름으로 사용한다. 참고로 지금처럼 스프링부트와 통합해서 사용하면 필드 이름을 테이블 컬럼 명으로 변경할 때 객체 필드의 카멜 케이스를 테이블 컬럼의 언더스코어로 자동으로 변환해준다. (itemName -> item_name, 따라서 위 예제의 @Column(name= "item_name") 를 생략해도 된다.)
- JPQL 직접 사용하기
public interface SpringDataJpaItemRepository extends JpaRepository<Item, Long> {
// 쿼리 메서드 기능
List<Item> findByItemNameLike(String itemName);
// 쿼리 직접 실행
@Query("select i from Item i where i.itemName like :itemName and i.price <= :price")
List<Item> findItems(@Param("itemName") String itemName, @Param("price") Integer price);
}
- 쿼리 메서드 기능 대신에 직접 JPQL 을 사용하고 싶을 때는 @Query와 함께 JPQL을 작성하면 된다. 이 때는 메서드 이름으로 실행하는 규칙은 무시된다.
- 스프링 데이터 JPA는 JPQL 뿐만 아니라 JPA의 네이티브 쿼리 기능도 지원하는데, JPQL 대신에 SQL 을 직접 작성할 수 있다.
인프런 ) 스프링DB 2편 - 데이터 접근 활용 기술 (김영한)
'Back > DB' 카테고리의 다른 글
[DB] 스프링 트랜잭션 (0) | 2023.05.18 |
---|---|
[DB] QueryDSL (0) | 2023.05.12 |
[DB] MyBatis (0) | 2023.05.09 |
[DB] JdbcTemplate (0) | 2023.05.08 |
[DB] H2 데이터베이스 설치 (0) | 2023.05.04 |