벌크란 여러 row들을 한번에 처리 하는 것.
근데 벌크는, 영속성 컨텍스트를 무시하고 직접 DB에 쿼리를 넣는다.
그래서, 만약 조회해 온 다음에 벌크를 하게 되면, 영속성 컨텍스트에 있는 데이터와 DB에 있는 데이터가 맞지 않을 수도 있다.
영속성 컨텍스트에 엔티티가 있으면 조회했을 때 그걸 주니까.
보통 그래서 해결책은
벌크연산 이후에 데이터를 조회해오거나
벌크연산 후 영속성 컨텍스트를 초기화 시켜버리는 것
https://qwefdg3.tistory.com/800
그래서 아예 스프링 Data JPA에서는 옵션을 제공해 줌
https://qwefdg3.tistory.com/886
이렇게 수정 등을 했을 때(delete도 수정) 자동으로 영속성 컨텍스트를 초기화 해 준다던지 그런 옵션이 있음.
@Test
@Commit
public void bulkUpdate(){
long count = query.update(m).set(m.username, "비회원").where(m.age.lt(28))
.execute();
assertThat(count).isEqualTo(2);
}
문법은 간단함
QueryFactory.update(엔티티).set(바꿀열, 데이터).where(대상조건).excute();
저런 업데이트 쿼리같은 건 execute()로 실행.
excute()는 영향받은 쿼리의 수를 반환
테스트 통과고, DB상에서 봐도 반영이 되었음.
/* update
Member member1
set
member1.username = ?1
where
member1.age < ?2 */ update member
set
username=?
where
age<?
정확히 친 데로 m.age가 < 28인 것의 username을 바꿈
@Test
public void bulkAdd(){
long count = query.update(m).set(m.age, m.age.add(1))
.execute();
assertThat(count).isEqualTo(4);
}
더할 때.
m.age.add() 이런 표현식이 있었음.
근데 minus같은 건 없음. 그냥 m.age.add(-1) 이런 식으로 하면 됨.
/* update
Member member1
set
member1.age = member1.age + ?1 */ update member
set
age=(age+cast(? as integer))
보면 m.age.add 하면 m.age + ? 이렇게 됨.
@Test
@Commit
public void bulkMultiple(){
long count = query.update(m).set(m.age, m.age.multiply(2))
.execute();
assertThat(count).isEqualTo(4);
}
곱하기는 있음.
divide() 라고 해서 나누기도 지원.
/* update
Member member1
set
member1.age = member1.age * ?1 */ update member
set
age=(age*cast(? as integer))
잘 나간다. SQL에서 값은 integer로 캐스팅해서 계산하는 것은 방어적으로 하기 위해 우선 integer인지 확인하는 용도 인 듯.
@Test
@Commit
public void bulkDelete(){
long count = query.delete(m).where(m.age.gt(18))
.execute();
assertThat(count).isEqualTo(3);
}
지우는 거
QueryFactory.delete(m).where(대상조건).excute()
/* delete
from
Member member1
where
member1.age > ?1 */ delete
from
member
where
age>?
delete 쿼리 잘 나감.
그러니까 벌크연산으로 일어날 수 있는 부작용이란게,
예를 들어 조회해 온 후,
그렇게 영속성 컨텍스트에 남아있는 상태에서 저 delete 벌크 연산을 때려버리면,
조회해올때 DB에 먼저 날리기 보다 영속성 컨텍스트에 있으면 그걸 반환해 주는데,
근데 delete 벌크 연산 날려서 이미 DB에는 없는데 영속성 컨텍스트에는 있어서 조회가 될 수도 있음.
그래서, 벌크연산 날린 후는 em.flush(), em.clear() 이렇게 해서 비워놔야 함.
'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글
27. 순수 JPA와 QueryDSL (0) | 2023.12.03 |
---|---|
26. SQL 함수 호출 (0) | 2023.12.02 |
24. 동적쿼리. Where 다중 파라미터 (0) | 2023.12.01 |
23. 동적쿼리. BooleanBuilder 방식 (0) | 2023.12.01 |
22. @QueryProjection (0) | 2023.12.01 |