JPA

JPA 기본기 다지기 Spring Data JPA와 QueryDSL

JANNNNNN 2024. 3. 27. 11:16
  • 지루하게 반복, 중복되는 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 정리

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();