Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 김영한
- 로그인
- 일론머스크
- 기본문법
- JPA
- Spring Data JPA
- API 개발 고급
- QueryDSL
- 스프링MVC
- 임베디드 타입
- JPA 활용2
- JPA 활용 2
- 트위터
- 페이징
- jpa 활용
- 불변 객체
- 값 타입 컬렉션
- 실무활용
- 벌크 연산
- 스프링
- 타임리프 문법
- 스프링 데이터 JPA
- Bean Validation
- 검증 애노테이션
- 컬렉션 조회 최적화
- 예제 도메인 모델
- 타임리프
- 스프링 mvc
- 프로젝트 환경설정
- JPQL
Archives
- Today
- Total
RE-Heat 개발자 일지
[Querydsl] [4] 중급 문법 (하편) - 동적 쿼리·벌크 연산·SQL function 본문
인프런 김영한 님의 강의를 듣고 작성한 글입니다.
■ 순수 JPA에서 동적 쿼리 사용 방법
1. 문자열 조합 : 오류 찾기 힘듦.
2. JPA Criteria : 어떤 JPQL이 실행될지 예상하기 어려움
■ Querydsl 동적쿼리 사용 방법
1. BooleanBuilder
2. Where 다중 파라미터 사용
[4] 동적 쿼리 - 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();
}
- if문으로 조건이 null값이 아니면 BooleanBuilder의 builder.and() 메서드를 통해 조건을 넣어준다.
- username과 age가 and 조건으로 들어간 것을 확인할 수 있다.(좌)
- 만일 ageParam에 null 값이 들어가면 SQL에도 age가 빠진다.(우)
■ 값을 필수로 넣고 싶으면?
[5] 동적 쿼리 - Where 다중 파라미터 사용
영한님이 실무에서 애용하는 방법
※ Tip - 인텔리 J에서 메소드의 위치를 바꾸고 싶으면 ctrl + shift 방향키 위아래를 누르면 된다.
테스트 코드
@Test
public void dynamicQuery_whereParam() throws Exception {
String usernameParam = "member1";
Integer ageParam = null;
List<Member> result = searchMember2(usernameParam, ageParam);
assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
.where(builder)
.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 값은 무시된다.
- 메서드를 다른 쿼리에서도 재활용할 수 있다(주목할 장점!!)
- 쿼리 자체의 가독성이 높아진다.
ageParam = null 기준 SQL
테스트 코드 - 메소드 조합
다른 예시
private Predicate allEq(String usernameCond, Integer ageCond){
return usernameEq(usernameCond).and(ageEq(ageCond));
}
- null 체크에 주의해야 한다.
[6] 수정, 삭제 벌크 연산
■ 쿼리 한 번으로 대량 데이터 수정
@Test
@Commit
public void bulkUpdate() throws Exception {
//member1 = 10 => 비회원
//member2 = 20 => 비회원
//member3 = 30 => 유지
//member4 = 40 => 유지
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
em.flush();
em.clear();
List<Member> result = queryFactory.selectFrom(member).fetch();
for (Member member1 : result) {
System.out.println("member1 = " + member1);
}
}
- 28세보다 어린 사람은 이름을 비회원으로 수정
- @Rollback(false)와 @Commit은 사실 같은 코드다.
- test에서 @Transactional을 하면 자동으로 롤백되는데, 실제로 DB에 들어갔는지 확인하려면 롤백을 하지 않도록 바꿔야 한다.
- 벌크 연산은 영속성 컨텍스트를 무시하고 DB에 날리므로 항상 실행 후 영속성 컨텍스트를 비워줘야 한다.
- 방법 1 : em.clear()
- 방법 2 : @Modifying(clearAutomatically = true)를 사용
- @Modifying 관련 자세한 내용은 [Spring Data JPA] [4] 쿼리 메소드 기능(하편)에서 확인
■ 숫자 곱하기
@Test
public void bulkMultiple() throws Exception {
long count = queryFactory
.update(member)
.set(member.age, member.age.multiply(2))
.execute();
}
- 곱셉은 .age.multiply()를 쓰고 원하는 배수를 () 안에 넣으면 된다.
- 더하기는 .age.add(1)로 해주면 된다.
- 빼기는 .age.add(-1)로 해주면 된다.
■ 벌크 연산 삭제하기
@Test
public void bulkDelete() throws Exception {
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
}
[7] SQL function 호출하기
SQL function은 JPA와 같이 Dialect에 등록된 내용만 호출할 수 있다.
■ Member → m으로 변경하기
@Test
public void sqlFunction() throws Exception {
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);
}
}
실제로 H2Dialect에 replace가 등록돼 있으며 필요하면 추가도 가능하다.
■ 소문자로 변경
@Test
public void sqlFunction2() throws Exception {
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);
}
}
① .where(member.username.eq(Expressions.stringTemplate("function('lower', {0})", member.username)))로 사용하는 방법
② lower 같은 ansi 표준 함수는 querydsl이 내장하고 있으므로 username.lower()만 해줘도 된다.
'백엔드 > Querydsl' 카테고리의 다른 글
[Querydsl] [6] 실무 활용 - 스프링 데이터 JPA와 Querydsl (0) | 2023.09.30 |
---|---|
[Querydsl] [5] 실무 활용 - 순수 JPA와 Querydsl (0) | 2023.09.30 |
[Querydsl] [4] 중급 문법 (상편) - 프로젝션 반환·@QueryProjection (0) | 2023.09.29 |
[Querydsl] [3] 기본 문법 (하편) (0) | 2023.09.17 |
[Querydsl] [3] 기본 문법 (상편) (0) | 2023.09.17 |