중급 문법 2

LeeKyoungChang·2022년 5월 6일
0
post-thumbnail

Querydsl 수업을 듣고 정리한 내용입니다.

 

📚 4. 동적 쿼리 - BooleanBuilder 사용

🔔 동적 쿼리를 해결하는 두 가지 방식

  • BooleanBuilder
  • Where 다중 파라미터 사용

 

BooleanBuilder 사용

@Test  
public void dynamicQuery_BooleanBuilder() throws Exception {  
    String usernameParam = "member1";  
    Integer ageParam = 10;  
  
    List<Member> result = searchMember1(usernameParam, ageParam);  
    assertThat(result.size()).isEqualTo(1);  
}  
  
private List<Member> searchMember1(String usernameCond, Integer ageCond) {  
    BooleanBuilder builder = new BooleanBuilder();  
    if (usernameCond != null) {  
        builder.and(member.username.eq(usernameCond));  
    }  
  
    if (ageCond != null) {  
        builder.and(member.age.eq(ageCond));  
    }  
  
  
    return queryFactory  
            .selectFrom(member)  
            .where(builder)  
            .fetch();  
}
  • BooleanBuilder를 통한 동적 쿼리 생성은 빌더를 생성 후 필요한 조건을 null 확인 여부에 따라 and 또는 or 등으로 더해주면 된다.

 

실행 결과

스크린샷 2022-05-06 오후 1 47 47

 

📚 5. 동적 쿼리 - Where 다중 파라미터 사용

    @Test  
    public void dynamicQuery_WhereParam() throws Exception {  
        String usernameParam = "member1";  
        Integer ageParam = 10;  
  
        List<Member> result = searchMember2(usernameParam, ageParam);  
        assertThat(result.size()).isEqualTo(1);  
    }  
  
    private List<Member> searchMember2(String usernameCond, Integer ageCond) {  
        return queryFactory  
                .selectFrom(member)  
                .where(usernameEq(usernameCond), ageEq(ageCond))  
//                .where(allEq(usernameCond, ageCond))  
                .fetch();  
    }  
  
    private BooleanExpression usernameEq(String usernameCond) {  
		 return usernameCond != null ? member.username.eq(usernameCond) : null;
    }  
  
    private BooleanExpression ageEq(Integer ageCond) {  
        return ageCond != null ? member.age.eq(ageCond) : null;  
    }
  • where 조건에 null 값은 무시된다.
  • usernameEq()와 같은 메서드를 다른 쿼리에서도 재활용할 수도 있다.
  • 쿼리 자체의 가독성이 높아진다.

 

실행 결과
스크린샷 2022-05-06 오후 3 29 25

 

✔️ 메서드 조합 가능

private BooleanExpression allEq(String usernameCond, Integer ageCond) {  
    return usernameEq(usernameCond).and(ageEq(ageCond));  
}
  • method chaining 가능
  • null 체크는 주의해서 처리해야 한다.

 

📚 6. 수정, 삭제 벌크 연산

✔️ 쿼리 한 번으로 대량 데이터 수정

@Test  
@Commit  
public void bulkUpdate() {  
  
    // member1 = 10 -> DB member1  
    // member2 = 20 -> DB member2    // member3 = 30 -> DB member3    // member4 = 40 -> DB member4  
    long count = queryFactory  
            .update(member)  
            .set(member.username, "비회원")  
            .where(member.age.lt(28))  
            .execute(); // count : 용량을 받은 회원 수  
  
    // member1 = 10 -> DB 비회원  
    // member2 = 20 -> DB 비회원  
    // member3 = 30 -> DB member3  
    // member4 = 40 -> DB member4  
    List<Member> result = queryFactory  
            .selectFrom(member)  
            .fetch();  
  
    for (Member member1 : result) {  
        System.out.println("member1 = " + member1);  
    }  
}
  • db상태와 영속성 컨텍스트 상태가 달라진다.
  • db → 영속성 컨텍스트에 데이터를 반영할 때, 영속성 컨텍스트에 데이터가 존재한다면 db 데이터는 버린다. (우선순위 : 영속성 컨텍스트, db)
  • 벌크연산을 실행하고 나면(영속성 컨텍스트에서 db로 데이터를 다 보냈다면), 영속성 컨텍스트 초기화 하기! (em.flush(), em.clear())

 

실행 결과
db
스크린샷 2022-05-06 오후 3 56 51

소스 실행
스크린샷 2022-05-06 오후 4 04 35

 

✔️ 기존 숫자에 1 더하기

@Test  
public void bulkAdd() {  
    long count = queryFactory  
            .update(member)  
            .set(member.age, member.age.add(1))  
            .execute();  
}
  • 곱하기는 multiply(x)

 

실행 결과

스크린샷 2022-05-06 오후 4 11 22

 

✔️ 쿼리 한번으로 대량 데이터 삭제

@Test  
public void builDelete() {  
    long count = queryFactory  
            .delete(member)  
            .where(member.age.gt(18))  
            .execute();  
}

 

실행 결과

스크린샷 2022-05-06 오후 4 13 44

 

❌ 주의
JPQL 배치와 마찬가지로, 영속성 컨텍스트에 있는 엔티티를 무시하고 실행되기 때문에 배치 쿼리를 실행하고 나면 영속성 컨텍스트를 초기화 하는 것이 안전하다.

 

📚 7. SQL function 호출하기

SQL function은 JPA와 같이 Dialect에 등록된 내용만 호출할 수 있다.

✔️ member → M으로 변경하는 replace 함수 사용

@Test  
public void sqlFunction() {  
    List<String> 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);  
    }  
}
  • memberM으로 변경된다.

 

실행 결과

스크린샷 2022-05-06 오후 4 23 34

 

✔️ lower 함수 - 소문자로 변경해서 비교

    @Test  
    public void sqlFunction2() {  
        List<String> result = queryFactory  
                .select(member.username)  
                .from(member)  
                .where(member.username.eq(  
                        Expressions.stringTemplate("function('lower', {0})", member.username)))  
//                .where(member.username.eq(member.username.lower()))  
                .fetch();  
  
        for (String s : result) {  
            System.out.println("s = " + s);  
        }  
    }

lower 같은 ansi 표준 함수들은 querydsl이 대부분 내장하고 있기 때문에 다음과 같이 처리해도 결과는 같다.

.where(member.username.eq(member.username.lower())) 

 

실행 결과

스크린샷 2022-05-06 오후 4 27 22

 

profile
"야, (오류 만났어?) 너두 (해결) 할 수 있어"

0개의 댓글