@Test
@Commit
public void bulkUpdate() {
// member1 = 10 -> 비회원
// member2 = 20 -> 비회원
// member3 = 30 -> 유지
// member4 = 40 -> 유지
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
}
➡️ 이렇게 10, 20살 회원은 비회원으로 바뀐 것을 확인 할 수 있다.
@Commit
: 해주지 않으면 롤백해버리기 때문에 H2에서 이렇게 결과를 확인할 수 없다.(= DB의 상태와 영속성 컨텍스트의 상태가 달라져버림)
member1 -> member1
member2 -> member2
member3 -> member3
member4 -> member4
여전히 이렇게 남아있고
member1 -> 비회원
member2 -> 비회원
member3 -> member3
member4 -> member4
변경되어 이렇게 남아있을 것.
DB의 내용은 무시하고 영속성 컨텍스트의 내용인 member1~4를 username으로 가져오게 된다.
➡️ 이렇게 벌크 연산 후 select해 출력 결과를 확인하면 영속성 컨텍스트의 내용을 출력시키는 것을 볼 수 있다.
em.flush();
em.clear();
그냥 영속성 컨텍스트에 있는걸 flush
해버리고 영속성 컨텍스트를 clear
해주자.
@Test
public void bulkAdd() {
long count = queryFactory
.update(member)
// add말고 따로 minus는 없음. add(-1)로 쓰면 됨.
// 곱하기는 multiply
.set(member.age, member.age.add(1))
.execute();
}
@Test
public void bulkDelete() {
queryFactory
.delete(member)
.where(member.age.gt(18)) // 18살 이상은 삭제
.execute();
}
📍결론: JPQL 배치와 마찬가지로, 영속성 컨텍스트에 있는 엔티티를 무시하고 실행되기 때문에 배치 쿼리를 실행하고 나면 영속성 컨텍스트를 초기화 하는 것이 안전하다.
SQL function은 JPA와 같이 Dialect데 등록된 내용만 호출할 수 있다.
@Test
public void sqlFunction() {
// 멤버의 이름을 모두 M으로 바꾸기
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);
}
}
@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이 상당부분 내장하고 있다. 따라서 위 코드와 같이 처리해도 같은 결과를 얻을 수 있다.