728x90
Spring Data JPA와 QueryDSL 이해
Spring Data JPA
소개
- 지루하게 반복, 중복되는 CRUD 문제를 세련된 방법으로 해결
- 개발자는 인터페이스만 작성
- 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입
적용 전
public class MemberRepository {
public void save(Member member) {...}
public Member findById(Long id) {...}
public List<Member> findAll() {...}
public Member findByUsername() {...}
}
적용 후
public interface MemberRepsoitory extends JpaRepository<Member, Long> {
List<Member> findByUsername(String username)
}
적용 후 클래스 다이어그램
구현 클래스 생성
공통 인터페이스 기능
public interface MemberRepsoitory extends JpaRepository<Member, Long> {
Member findByUsername()
}
- JpaRepository 인터페이스 : 공통 CRUD 제공
- 제네릭은 <엔티티, 식별자>로 설정
메서드 이름만으로 JPQL 쿼리 생성
public interface MemberRepsoitory extends JpaRepository<Member, Long> {
List<Member> findByUsername(String username); // 검색
List<member> findByUsername(String username, Sort sort); // 검색 + 정렬
List<Member> findByUsername(String username, Pageable Pagealbe); // 검색 + 정렬 + 페이징
}
@Query, JPQL 정리
- @Query를 사용해서 직접 JPQL 지정
public interface MemberRepsoitory extends JpaRepository<Member, Long> {
@Query("SELECT m FROM Member m WHERE m.username = ?1")
List<Member> findByUsername(String username);
}
반환타입
- 단건, 컬렉션 모두 가능하다.
Web 페이징 과 정렬 기능
web 도메인 클래스 컨버터 기능
- 컨트롤러에서 식별자로 도메인 클래스 찾음
QueryDSL
소개
- SQL, JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API
- JPA 크리테리아에 비해서 편리하고 실용적임
- 오픈소스
SQL, JPQL의 문제점
- SQL, JPQL은 문자, Type-check 불가능
- 해당 로직 실행 전까지 작동여부 확인 불가
장점
- 문자가 아닌 코드로 작성
- 컴파일 시점에 문법 오류 발견
- 코드 자동완성(IDE 도움)
- 단순하고 쉬움 : 코드 모양이 JPQL과 거의 비슷
- 동적 쿼리
쿼리타입 생성
사용
// JPQL
SELECT m FROM Member m WHERE m.age>18;
// QueryDSL
JPAFactoryQuery query=new JPAQueryFactory(entityManager);
QMember qMember=QMember.member;
List<Member> mebers=query.selectFROM(qMember)
.where(qMember.age.at(18)
.orderBy(qMember.name.desc())
.fetch();
- 조인
JPAFactoryQuery query=new JPAQueryFactory(entityManager);
QMember qMember=QMember.member;
QTeam qTeam=QTeam.team;
List<Member> mebers=query.selectFROM(qMember)
.join(qMember.team,qTeam)
.where(qTeam.name.eq("teamA")
.fetch();
- 페이징 API
JPAFactoryQuery query=new JPAQueryFactory(entityManager);
QMember qMember=QMember.member;
List<Member> mebers=query.selectFROM(qMember)
.orderBy(qMember.age.desc())
.offset(10)
.limit(20)
.fetch();
- 동적 쿼리
String name="Member A";
int age=9;
QMember m=QMember.member;
BooleanBuilder builder=new BooleanBuilder();
if(name!=null){
Builder.and(m.name.contains(name);
if(age!=0){
builder.and(m.age.gt(age));
}
List<Member> members=query.selectFrom(m)
.where(builder)
.fetch();
- 이것은 자바다!
실무 경험 공유
- 테이블 중심에서 객체 중심으로 개발 패러다임이 변화
- 유연한 데이터베이스 변경의 장점과 테스트
- JUnit 통합 테스트시에 H2 DB 메모리 모드
- 로컬 PC에는 H2 DB 서버 모드로 실행
- 개발 운영은 MySQL, Oracle
- 테스트, 통합 테스트시에 CRUD는 믿고 간다.
- 빠른 오류 발견
- 컴파일 시점
- 늦어도 애플리케이션 로딩 시점
- 최소한 쿼리 문법 실수나 오류는 거의 발생하지 않는다.
성능
- JPA 자체로 인한 성능 저하 이슈는 거의 없음
- 성능 이슈 대부분은 JPA를 잘 이해하지 못해서 발생
- 즉시 로딩 : 쿼리가 튐 → 지연 로딩으로 변경
- N + 1 문제 → 대부분 페치 조인으로 해결
- 내부 파서 문제 : 2000줄 짜리 동적 쿼리 생성 1초
- 정적 쿼리로 변경 (하이버네이트는 파싱된 결과 재사용)
생산성
- 단순 코딩 시간 줄어듬 → 개발 생산성 향상 → 잉여 시간 발생
- 비즈니스 로직 작성시 흐름이 끊기지 않음
- 남는 시간에 더 많은 테스트 작성
- 남는 시간에 기술 공부
- 남는 시간에 코드 리팩토링
- 팀원 대부분 다시는 과거로 돌아가고 싶어하지 않음
많이 하는 질문
- ORM 프레임워크를 사용하면 SQL과 데이터베이스는 잘 몰라도 되나요?
- 둘다 잘 알아야 한다.
- 성능은 느리지 않나요?
- 최적화 하는 방법이 다 있다.
- 통계 쿼리처럼 매우 복잡한 SQL은 어떻게 하나요?
- QueryDSL로 왠만하면 가능하지만, 네이티브 쿼리도 사용한다.
- MyBatis와 어떤 차이가 있나요?
- 쿼리랑 SQL 매핑하지만, JPA는 쿼리도 필요없다.
- 하이버네이트 프레임워크를 신뢰할 수 있나요?
- 신뢰 가능(실제 대규모 서비스에서 사용)
출처
[토크ON세미나] JPA 프로그래밍 기본기 다지기 8강 - Spring Data JPA와 QueryDSL 이해 | T아카데미
728x90
728x90
'Lecture > [Tacademy] JPA 프로그래밍 기본기 다지기' 카테고리의 다른 글
7. JPA 객체지향 쿼리 (0) | 2020.12.17 |
---|---|
6. JPA 내부구조 (0) | 2020.12.16 |
5. 양방향 매핑 (0) | 2020.12.15 |
4. 연관관계 매핑 (0) | 2020.12.15 |
3. 필드와 컬럼 매핑 (0) | 2020.12.13 |