스프링 데이터 JPA가 제공하는 Querydsl 기능
2022. 7. 28. 15:15
Querydsl
여기서 소개하는 기능은 제약이 커서 복잡한 실무 환경에서 사용하기에는 많이 부족하다. 그래도 스프링 데이터에서 제공하는 기능이므로 간단히 소개하고, 왜 부족한지 설명하겠다. 인터페이스 지원 - QuerydslPredicateExecutor QuerydslPredicateExecutor 인터페이스 public interface QuerydslPredicateExecutor { Optional findById(Predicate predicate); Iterable findAll(Predicate predicate); long count(Predicate predicate); boolean exists(Predicate predicate); // … more functionality omitted. } 리포지..
스프링 데이터 페이징 활용3 - 컨트롤러 개발
2022. 7. 27. 01:32
Querydsl
실제 컨트롤러 @RestController @RequiredArgsConstructor public class MemberController { private final MemberJpaRepository memberJpaRepository; private final MemberRepository memberRepository; @GetMapping("/v1/members") public List searchMemberV1(MemberSearchCondition condition) { return memberJpaRepository.search(condition); } @GetMapping("/v2/members") public Page searchMemberV2(MemberSearchCondition ..
스프링 데이터 페이징 활용2 - CountQuery 최적화
2022. 7. 27. 01:04
Querydsl
PageableExecutionUtils.getPage()로 최적화 @Override public Page searchComplex(MemberSearchCondition condition, Pageable pageable) { List content = queryFactory .select(new QMemberTeamDto( member.id, member.username, member.age, team.id, team.name)) .from(member) .leftJoin(member.team, team) .where(usernameEq(condition.getUsername()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe())..
스프링 데이터 페이징 활용1 - Querydsl 페이징 연동
2022. 7. 26. 22:20
Querydsl
스프링 데이터의 Page, Pageable을 활용해보자. 전체 카운트를 한번에 조회하는 단순한 방법 데이터 내용과 전체 카운트를 별도로 조회하는 방법 사용자 정의 인터페이스에 페이징 2가지 추가 public interface MemberRepositoryCustom { List search(MemberSearchCondition condition); Page searchPageSimple(MemberSearchCondition condition, Pageable pageable); Page searchComplex(MemberSearchCondition condition, Pageable pageable); } 전체 카운트를 한번에 조회하는 단순한 방법 searchPageSimple(), fetchRes..
사용자 정의 리포지토리
2022. 7. 26. 21:27
Querydsl
사용자 정의 리포지토리 사용법 1. 사용자 정의 인터페이스 작성 2. 사용자 정의 인터페이스 구현 3. 스프링 데이터 리포지토리에 사용자 정의 인터페이스 상속 사용자 정의 리포지토리 구성 1. 사용자 정의 인터페이스 작성 public interface MemberRepositoryCustom { List search(MemberSearchCondition condition); } 2. 사용자 정의 인터페이스 구현 public class MemberRepositoryImpl implements MemberRepositoryCustom { private final JPAQueryFactory queryFactory; public MemberRepositoryImpl(EntityManager em) { thi..
실무 활용 - 스프링 데이터 JPA와 Querydsl
2022. 7. 26. 16:52
Querydsl
스프링 데이터 JPA 리포지토리로 변경 스프링 데이터 JPA - MemberRepository 생성 public interface MemberRepository extends JpaRepository { List findByUsername(String username); } 스프링 데이터 JPA 테스트 @SpringBootTest @Transactional class MemberRepositoryTest { @Autowired EntityManager em; @Autowired MemberRepository memberRepository; @Test public void basicTest() { Member member = new Member("member1", 10); memberRepository.s..
조회 API 컨트롤러 개발
2022. 7. 26. 16:43
Querydsl
편리한 데이터 확인을 위해 샘플 데이터를 추가하자. 샘플 데이터 추가가 테스트 케이스 실행에 영향을 주지 않도록 다음과 같이 프로파일을 설정하자 프로파일 설정 src/main/resources/application.yml spring: profiles: active: local 테스트는 기존 application.yml을 복사해서 다음 경로로 복사하고, 프로파일을 test로 수정하자 spring: profiles: active: test 이렇게 분리하면 main 소스코드와 테스트 소스 코드 실행시 프로파일을 분리할 수 있다. 샘플 데이터 추가 @Profile("local") @Component @RequiredArgsConstructor public class InitMember { private fin..
동적 쿼리와 성능 최적화 조회 - Where절 파라미터 사용
2022. 7. 26. 16:22
Querydsl
Where절에 파라미터를 사용한 예제 public List search(MemberSearchCondition condition) { return queryFactory .select(new QMemberTeamDto( member.id.as("memberId"), member.username, member.age, team.id.as("teamId"), team.name.as("teamName"))) .from(member) .leftJoin(member.team, team) .where(usernameEq(condition.getUsername()), teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition..
동적 쿼리와 성능 최적화 조회 - Builder 사용
2022. 7. 26. 16:02
Querydsl
MemberTeamDto - 조회 최적화용 DTO 추가 @Datapublic class MemberTeamDto { private Long memberId; private String username; private int age; private Long teamId; private String teamName; @QueryProjection public MemberTeamDto(Long memberId, String username, int age, Long teamId, String teamName) { this.memberId = memberId; this.username = username; this.age = age; this.teamId = teamId; this.teamName = teamN..
실무 활용 - 순수 JPA와 Querydsl
2022. 7. 26. 15:28
Querydsl
순수 JPA 리포지토리와 Querydsl 순수 JPA 리포지토리 @Repository public class MemberJpaRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public MemberJpaRepository(EntityManager em) { this.em = em; this.queryFactory = new JPAQueryFactory(em); } public void save(Member member) { em.persist(member); } public Optional findById(Long id) { Member findMember = em.find(Member.clas..
SQL function 호출하기
2022. 7. 26. 01:09
Querydsl
SQL function은 JPA와 같이 Dialect에 등록된 내용만 호출할 수 있다. member M으로 변경하는 replace 함수 사용 @Test public void sqlFunction() { List result = queryFactory .select( Expressions.stringTemplate("function('replace', {0}, {1}, {2})", member.username, "member", "M")) .from(member) .fetch(); for (String s : result) { System.out.println("s = " + s); } } 소문자로 변경해서 비교해라 @Test public void sqlFunction2() { List result = q..
수정, 삭제 벌크 연산
2022. 7. 26. 00:57
Querydsl
쿼리 한번으로 대량 데이터 수정 @Test public void bulkUpdate() { long count = queryFactory .update(member) .set(member.username, "비회원") .where(member.age.lt(28)) .execute(); } 기존 숫자에 1 더하기 long count = queryFactory .update(member) .set(member.age, member.age.add(1)) .execute(); 곱하기: multiply(x) 쿼리 한번으로 대량 데이터 삭제 long count = queryFactory .delete(member) .where(member.age.gt(18)) .execute(); 주의: JPQL 배치와 마찬가지로..
동적 쿼리 - Where 다중 파라미터 사용
2022. 7. 25. 23:45
Querydsl
동적 쿼리 - Where 다중 파라미터 사용 @Test public void dynamicQuery_WhereParam() { String usernameParam = "member1"; Integer ageParam = 10; List result = searchMember2(usernameParam, ageParam); assertThat(result.size()).isEqualTo(1); } private List searchMember2(String usernameCond, Integer ageCond) { return queryFactory .selectFrom(member) // .where(usernameEq(usernameCond), ageEq(ageCond)) .where(allEq(us..
동적 쿼리 - BooleanBuilder 사용
2022. 7. 25. 23:26
Querydsl
동적 쿼리를 해결하는 두가지 방식 BooleanBuilder Where 다중 파라미터 사용 @Test public void dynamicQuery_BooleanBuilder() { String usernameParam = "member1"; Integer ageParam = 10; List result = searchMember1(usernameParam, ageParam); assertThat(result.size()).isEqualTo(1); } private List searchMember1(String usernameCond, Integer ageCond) { BooleanBuilder builder = new BooleanBuilder(); if (usernameCond != null) { bu..
프로젝션과 결과 반환 - @QueryProjection
2022. 7. 25. 20:51
Querydsl
생성자 + @QueryProjection @Data public class MemberDto { private String username; private int age; public MemberDto() { } @QueryProjection public MemberDto(String username, int age) { this.username = username; this.age = age; } } ./gradlew compileQuerydsl QMemberDto 생성 확인 @QueryProjection 활용 @Test public void findDtoByQueryProjection() { List result = queryFactory .select(new QMemberDto(member.user..
프로젝션과 결과 반환 - DTO 조회
2022. 7. 25. 16:35
Querydsl
순수 JPA에서 DTO 조회 MemberDto @Data public class MemberDto { private String username; private int age; public MemberDto(String username, int age) { this.username = username; this.age = age; } } 순수 JPA에서 DTO 조회 코드 @Test public void findDtoByJPQL() { List result = em.createQuery("select new study.querydsl.dto.MemberDto(m.username, m.age) from Member m", MemberDto.class) .getResultList(); for (MemberDt..
프로젝션과 결과 반환 - 기본
2022. 7. 25. 15:45
Querydsl
프로젝션: select 대상 지정 프로젝션 대상이 하나 @Test public void simpleProjection() { List result = queryFactory .select(member.username) .from(member) .fetch(); for (String s : result) { System.out.println("s = " + s); } } 프로젝션 대상이 하나면 타입을 명확하게 지정할 수 있음 프로젝션 대상이 둘 이상이면 튜플이나 DTO로 조회 튜플 조회 프로젝션 대상이 둘 이상일 때 사용 com.querydsl.core.Tuple @Test public void tupleProjection() { List result = queryFactory .select(member...
상수, 문자 더하기
2022. 7. 25. 15:35
Querydsl
상수가 필요하면 Expressions.constant(xxx) 사용 @Test public void constant() { List result = queryFactory .select(member.username, Expressions.constant("A")) .from(member) .fetch(); for (Tuple tuple : result) { System.out.println("tuple = " + tuple); } } 결과 : member1, A 참고: 위와 같이 최적화가 가능하면 SQL에 constant 값을 넘기지 않는다. 상수를 더하는 것 처럼 최적화가 어려우면 SQL에 constant 값을 넘긴다. 문자 더하기 concat @Test public void concat() { Lis..
Case 문
2022. 7. 25. 15:24
Querydsl
select, 조건절(where), order by에서 사용 가능 단순한 조건 @Test public void basicCase() { List result = queryFactory .select(member.age .when(10).then("열살") .when(20).then("스무살") .otherwise("기타")) .from(member) .fetch(); for (String s : result) { System.out.println("s = " + s); } } 복잡한 조건 @Test public void complexCase() { List result = queryFactory .select(new CaseBuilder() .when(member.age.between(0, 20)).th..
서브 쿼리
2022. 7. 25. 13:31
Querydsl
com.querydsl.jpa.JPAExpressions 사용 서브 쿼리 eq 사용 /** * 나이가 가장 많은 회원 조회 */@Test public void subQuery() throws Exception { QMember memberSub = new QMember("memberSub"); List result = queryFactory .selectFrom(member) .where(member.age.eq( JPAExpressions .select(memberSub.age.max()) .from(memberSub) )) .fetch(); assertThat(result).extracting("age") .containsExactly(40); } 서브 쿼리 goe 사용 @Test public voi..