스프링 데이터 JPA 소개
- JPA 를 편리하게 사용하도록 도와주는 프레임워크이다.
- 리파지토리의 구현 클래스 없이 인터페이스만으로 개발이 가능하다.
- 기본 CRUD 기능과 페이지 기능도 자동 제공된다.
- 쿼리 메서드 기능을 제공한다.
- 동적 SQL 을 해결하기 어렵다.
초기 설정
build.gradle 파일에 다음 설정을 추가해 준다.
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
(JPA 라이브러리에 JDBC 라이브러리도 함께 포함되어 있기 때문에, JDBC 의존관계를 제거해도 된다.)
`main` 과 `test` 의 application.properties 에 다음 설정을 추가해 준다.
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE
`org.hibernate.SQL=DEBUG` : 하이버네이트가 생성하고 실행하는 SQL 을 `logger` 를 통해 확인할 수 있다.
`logging.level.org.hibernate.orm.jdbc.bind=TRACE` : SQL 에 바인딩되는 파라미터를 확인할 수 있다.
(`spring.jpa.show-sql=true` 도 실행하는 SQL 을 확인할 수 있지만, `System.out` 을 통해 출력되기 때문에 권장하지 않는다.)
공통 인터페이스 기능
- `JpaRepository` 인터페이스를 통해 기본적인 CRUD 기능을 제공한다.
- 공통화 가능한 기능이 거의 모두 포함되어 있다.
public interface ItemRepository extends JpaRepository<Item, Long> {
}
`JpaRepository` 인터페이스를 인터페이스 상속을 받아, 제네릭에 관리할 `<엔티티, 엔티티ID>` 를 주면 된다.
그러면 `JpaRepository` 가 제공하는 기본 CRUD 기능을 모두 사용할 수 있다.
> 참고 <
`JpaRepository` 인터페이스만 상속받으면 스프링 데이터 JPA 가 프록시 기술을 사용하여 구현 클래스를 만들어 스프링 빈으로 자동 등록한다.
쿼리 메서드 기능
인터페이스에 메서드만 적어주면, 메서드 이름을 분석하여 쿼리를 자동으로 만들고 실행해주는 기능이다.
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
메서드 이름을 분석해서 필요한 JPQL 을 만들어 실행한다.
(JPA 가 JPQL 을 SQL 로 번역하여 실행한다.)
조회 : `find_By`, `read_By`, `query_By`, `get_By`
COUNT : `count_By` / 반환타입 long
EXISTS : `exists_By` / 반환타입 boolean
삭제 : `delete_By`, `remove_By` / 반환타입 long
DISTINCT : `findDistinct`, `findMemberDistinctBy`
LIMIT : `findFirst3`, `findFirst`, `findTop`, `findTop3`
@Query
- 쿼리를 직접 실행할 수 있다.
- 파라미터를 @Param 애노테이션을 통해 명시적으로 바인딩해야 한다.
@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);
스프링 데이터 JPA 사용 예시
Spring Data JPA 리포지토리
public interface SpringDataJpaItemRepository extends JpaRepository<Item, Long> {
List<Item> findByItemNameLike(String itemName);
List<Item> findByPriceLessThanEqual(Integer price);
List<Item> findByItemNameLikeAndPriceLessThanEqual(String itemName, Integer price);
// 쿼리 직접 실행
@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);
}
`findByItemNameLikeAndPriceLessThanEqual` 과 `findItems` 는 같은 기능을 수행한다.
리포지토리
@Repository
@Transactional
@RequiredArgsConstructor
public class JpaItemRepository implements ItemRepository {
private final SpringDataJpaItemRepository repository;
@Override
public Item save(Item item) {
return repository.save(item);
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findItem = repository.findById(itemId).orElseThrow();
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
@Override
public Optional<Item> findById(Long id) {
return repository.findById(id);
}
@Override
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
if (StringUtils.hasText(itemName) && maxPrice != null) {
return repository.findItems("%" + itemName + "%", maxPrice);
} else if (StringUtils.hasText(itemName)) {
return repository.findByItemNameLike("%" + itemName + "%");
} else if (maxPrice != null) {
return repository.findByPriceLessThanEqual(maxPrice);
} else {
return repository.findAll();
}
}
}
Udate
- 트랜잭션이 커밋될 때 변경 내용이 데이터베이스에 반영된다.
Spring Data JPA 리포지토리
`JpaRepository` 를 상속한 인터페이스는 스프링 데이터 JPA 내부에서 자동으로 구현 클래스(프록시 객체)를 생성하여 빈으로 등록한다.
따라서 스프링 예외 추상화를 지원하기 때문에, @Repository 와 관계없이 예외가 변환된다.
(하지만 직접 작성하는 리포지토리 구현 클래스에서는 @Repository를 붙여야 예외 변환이 적용된다.
왜냐하면, 스프링은 @Repository 가 붙은 클래스에만 `PersistenceExceptionTranslationPostProcessor` 를 통해 예외 변환 AOP를 적용하기 때문이다.)
출처 | 스프링 DB 2(김영한) - 인프런
'💠프로그래밍 언어 > Spring' 카테고리의 다른 글
[Spring] 트랜잭션 옵션과 전파에 대하여, 그리고 트랜잭션 주의사항까지 (0) | 2025.05.02 |
---|---|
[Spring] Querydsl 을 통해 동적 쿼리 해결하기 (1) | 2025.05.02 |
[Spring] JPA 소개 및 사용 예시 (0) | 2025.05.02 |
[Spring] MyBatis 사용법 익히기 ! (1) | 2025.05.01 |
[Spring] 데이터베이스 연동하여 테스트하기 ! (별도 DB, 임베디드 모드) (0) | 2025.05.01 |