Go, Vantage point
가까운 곳을 걷지 않고 서는 먼 곳을 갈 수 없다.
Github | https://github.com/overnew/
Blog | https://everenew.tistory.com/
티스토리 뷰
* 김영한님의 스프링 DB 2편 강좌를 수강하며 정리한 글입니다. *
이전 글에서는 JPA에 대해 정리하였다.
Spring Data JPA
관계형 DB만 존재하던 시절에서, 이제는 NoSQL DB도 많이 사용되고 있다.
서로의 패러다임과 구현 기술이 다르더라도 결국의 CRUD 기능은 동일하다.
다양한 DB들을 더 큰 관점에서 추상화한 것이 Spring Data JPA이다.
물론, Spring Data JPA는 JPA를 잘 활용하는 도구로 사용해야 한다.
편리한 최신 기술들도 결국에는 거들 뿐이므로, SQL이나 DB의 이해도 분명히 필요하다.
JpaRepository 사용하기
JpaRepository<Entity, Entity PK Type> 인터페이스를 상속하면 기본적인 CRUD 기능을 바로 제공해준다.
<Entity>는 해당 Entity를 관리함을 명시한다.
인터페이스 상속만으로 이것이 가능한 이유는 Spring Data JPA가 동적 프록시 기술로 구현체를 생성해 주기 때문이다.
이 구현체는 스프링 빈으로 등록된다.
메서드 이름만 적어도 이름을 분석해 자동으로 쿼리를 만들어 실행하는 무시무시한 기능도 있다;;
Spring Data JPA가 JPQL을 만들고 JPA가 SQL로 변환해 실행하는 식이다.
물론 메서드 이름에는 규칙이있다.
find(설명)By(조건).. 이런 식으로 생성한다.
자세한 내용은 공식 문서를 참조하자.
예를 들어 아래와 같은 메서드 명은 다음과 같이 JPQL로 바뀐다.
List<Item> findByItemNameLikeAndPriceLessThanEqual(String itemName, Integer price)
select i from Item i where i.itemName like :itemName and i.price <= :price
이처럼 조건이 많은 메서드 명은 너무 난잡하므로 @Query 애노테이션을 적용해 직접 쿼리를 실행하자.
@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);
public interface SpringDataJpaItemRepository extends JpaRepository<Item,Long> {
//기본적 CRUD는 상속만으로도 사용가능
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);
}
추가적으로 Spring Data JPA를 이용하면 스프링 예외 변환을 적용해주므로 @Repository를 적용할 필요가 없다.
QueryDsl
JPA도 여전히 동적 쿼리 생성에는 취약점이 있다.
여러 가지 조건의 SELECT 구문이라면 동적 쿼리 생성은 더욱 까다로워 진다.
특히 Query문들은 IDE가 체크해주는 type이 아닌 그저 문자열이므로 오류가 나기 쉽다.
쿼리를 Java 코드로 작성해, IDE와 컴파일러가 잡아주는 Type-safe 기능을 제공하는 것이 바로 QueryDsl이다.
DSL은 Domain Specific Language의 약자로 도메인 특화 언어이다.
QueryDsl은 쿼리에 특화된 언어라 보면된다.
이는 여러 DB들의 쿼리 기능을 추상화하려는 목적에서 시작했다.
QueryDsl - JPA는 JPQL 작성을 위해 만들어졌다.
QueryDsl로 JPQL 을 생성하고, JPQL로 SQL을 생성하는 방식이다.
QueryDsl 또한 JPQL을 모르고 사용하는 것은 사상누각이 되니 주의하자.
Querydsl은 JPAQueryFactory를 사용해, JPQL을 만든다.
이때 JPA도 사용해야 하므로 EntityManager를 통해 생성해주자.
private final EntityManager em;
private final JPAQueryFactory query; //QueryDSL이 JPQL을 만드는 것
public JpaItemRepositoryV3(EntityManager em) {
this.em = em;
this.query = new JPAQueryFactory(em);
}
이제 쿼리 조건을 자바 메서드로 작성할 수 있기 때문에 재사용이 가능해진다.
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
List<Item> result = query
.select(item)
.from(item)
.where(likeItemName(itemName), maxPrice(maxPrice))
.fetch(); //동적 쿼리를 메서드로 작성가능 해짐
return result;
}
private BooleanExpression likeItemName(String itemName){
if(StringUtils.hasText(itemName)){
return item.itemName.like("%"+itemName + "%");
}
return null; //조건 무시
}
private BooleanExpression maxPrice(Integer maxPrice) {
if(maxPrice != null){
return item.price.loe(maxPrice);
}
return null; //조건 무시
}
오타가 있어도 컴파일러와 IDE가 잡아주기 때문에 생산성도 올라간다.
QueryDsl은 예외 변환은 제공하지 않기 때문에 @Repository를 적용시키자.
'개발 > Spring DataBase' 카테고리의 다른 글
[Spring DB] 12. 스프링 트랜잭션 전파 (0) | 2022.07.31 |
---|---|
[Spring DB] 11. Spring Transaction (0) | 2022.07.30 |
[Spring DB] 9. JPA (0) | 2022.07.27 |
[Spring DB] 8. MyBatis (0) | 2022.07.26 |
[Spring DB] 7. DataBase Test, 임베디드 DB (0) | 2022.07.25 |