-
[스프링부트/웹 애플리케이션 개발]스프링 데이터 JPA, QueryDSL스프링&스프링부트 2023. 1. 17. 16:23
스프링 데이터 JPA
( https://spring.io/projects/spring-data-jpa )
- 스프링 데이터 JPA는 JPA를 사용할 때 지루하게 반복하는 코드를 자동화
MemberRepository
package jpabook.jpashop.repository; import jpabook.jpashop.domain.Member; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import javax.persistence.EntityManager; import java.util.List; @Repository @RequiredArgsConstructor public class MemberRepository { private final EntityManager em; public void save(Member member) { em.persist(member); } public Member findOne(Long id) { return em.find(Member.class, id); } public List<Member> findAll() { return em.createQuery("select m from Member m", Member.class).getResultList(); } public List<Member> findByName(String name) { return em.createQuery("select m from Member m where m.name = :name", Member.class) .setParameter("name", name) .getResultList(); } }
스프링 데이터 JPA 적용
package jpabook.jpashop.repository; import jpabook.jpashop.domain.Member; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface MemberRepository extends JpaRepository<Member, Long> { List<Member> findByName(String name); }
- findOne() findById()로 변경
- 스프링 데이터 JPA는 JpaRepository 라는 인터페이스를 제공하는데, 여기에 기본적인 CRUD 기능이 모두 제공
- findByName 처럼 일반화 하기 어려운 기능도 메서드 이름으로 정확한 JPQL 쿼리를 실행한다.
> select m from Member m where m.name = :name
- 개발자는 인터페이스만 만들면 된다. 구현체는 스프링 데이터 JPA가 애플리케이션 실행시점에 주입해준다
>> 스프링 데이터 JPA는 JPA를 사용해서 이런 기능을 제공할 뿐이다. 결국 JPA 자체를 잘 이해하는 것이 가장 중요
QueryDSL
- Querydsl은 SQL(JPQL)과 모양이 유사하면서 자바 코드로 동적 쿼리를 편리하게 생성할 수 있다.
orderRepository
public List<Order> findAll(OrderSearch orderSearch) { //JPAQueryFactory query = new JPAQueryFactory(em); QOrder order = QOrder.order; QMember member = QMember.member; // static으로 코드 줄일 수 있음 return query .select(order) .from(order) .join(order.member, member) .where(statusEq(orderSearch.getOrderStatus()), nameLike(orderSearch.getMemberName())) //동적쿼리 //.where(order.status.eq(orderSearch.getOrderStatus())) > 정적쿼리 .limit(1000) .fetch(); } private Predicate nameLike(String memberName) { if (!StringUtils.hasText(memberName)) { return null; } return QMember.member.name.like(memberName); } private BooleanExpression statusEq(OrderStatus statusCond) { if (statusCond == null) { return null; } return QOrder.order.status.eq(statusCond); }
build.gradle 코드 추가
//querydsl 추가 buildscript { ext { queryDslVersion = "5.0.0" } } plugins { id 'java' id 'org.springframework.boot' version '2.7.7' id 'io.spring.dependency-management' version '1.0.15.RELEASE' id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } group = 'jpabook' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //querydsl 추가 implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" implementation "com.querydsl:querydsl-apt:${queryDslVersion}" } tasks.named('test') { useJUnitPlatform() } test { useJUnitPlatform() } //querydsl 추가 def querydslDir = "$buildDir/generated/querydsl" querydsl { jpa = true querydslSourcesDir = querydslDir } sourceSets { main.java.srcDir querydslDir } compileQuerydsl{ options.annotationProcessorPath = configurations.querydsl } configurations { compileOnly { extendsFrom annotationProcessor } querydsl.extendsFrom compileClasspath }
- 동작은 되는데 generate에 파일들이 보이지 않음...?
- 오류 발생해서 ( https://jaimemin.tistory.com/2120 ) 참고
실무에서는 복잡한 동적 쿼리를 많이 사용하게 되는데, 이때 Querydsl을 사용하면 높은 개발 생산성을 얻으면서 동시에 쿼리 오류를 컴파일 시점에 빠르게 잡을 수 있다. 꼭 동적 쿼리가 아니라 정적 쿼리인 경우에도 다음과 같은 이유로 Querydsl을 사용하는 것이 좋다.
- 직관적인 문법
- 컴파일 시점에 빠른 문법 오류 발견
- 코드 자동완성
- 코드 재사용(이것은 자바다)
- JPQL new 명령어와는 비교가 안될 정도로 깔끔한 DTO 조회를 지원한다.
728x90'스프링&스프링부트' 카테고리의 다른 글
[spring] DTO 와 VO 무슨 차이가 있을까 (0) 2024.08.14 [springboot] 의존성주입(DI)와 순환참조 문제 해결 (0) 2024.08.14 [스프링부트/웹 애플리케이션 개발]API 개발 고급 - 실무 필수 최적화 (0) 2023.01.17 [스프링부트/웹 애플리케이션 개발]API 개발 고급 정리 (0) 2023.01.16 [스프링부트/웹 애플리케이션 개발]API 개발 고급 - 컬렉션 조회 최적화 -4,5,6 (0) 2023.01.16