@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void bulkUpdate() {
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
}
}
update member
set username=?
where age < ?
update member
set username=NULL
where age < ?
m = Member(id=3, username=비회원, age=10)
m = Member(id=4, username=비회원, age=20)
m = Member(id=5, username=member3, age=30)
m = Member(id=6, username=member4, age=40)
JPA는 영속성 컨텍스트에 엔티티를 올려놓는다.
벌크 연산을 하게 되면 모든 데이터가 영속성 컨텍스트에 올라가게 된다.
그런데 벌크 연산은 영속성 컨텍스트를 무시하고 바로 쿼리를 보낸다.
따라서 DB 상태와 영속성 컨텍스트의 상태가 달라진다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void bulkUpdate() {
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
List<Member> result = queryFactory
.selectFrom(member)
.fetch();
for (Member m : result) {
System.out.println("m = " + m);
}
}
}
m = Member(id=3, username=member1, age=10)
m = Member(id=4, username=member2, age=20)
m = Member(id=5, username=member3, age=30)
m = Member(id=6, username=member4, age=40)
만약 벌크 연산 후 조회 로직을 넣는다면?
이미 영속성 컨텍스트에 해당 id로 값이 있기 때문에 영속성 컨텍스트의 데이터가 우선적으로 보여진다.
즉, DB에 비회원이라고 업데이트된 것과는 다른 값이 출력된다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void bulkUpdate() {
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 m : result) {
System.out.println("m = " + member1);
}
}
}
m = Member(id=3, username=비회원, age=10)
m = Member(id=4, username=비회원, age=20)
m = Member(id=5, username=member3, age=30)
m = Member(id=6, username=member4, age=40)
flush를 해줘서 영속성 컨텍스트와 DB를 맞춘 뒤, clear로 초기화 한다.
대량 데이터 1씩 더하기
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void bulkUpdate() {
long count = queryFactory
.update(member)
.set(member.age, member.age.add(1))
.execute();
}
}
update member set age=age+?
update member set age=age+NULL
곱하기는 multiply()를 사용할 수 있다.
대량 데이터 삭제
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void bulkUpdate() {
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
}
}
delete from member where age>?
delete from member where age>NULL