본문 바로가기

Spring Data JPA

3월 22일 SpringDataJPA 벌크성 수정 쿼리

DB에 update 쿼리 1번으로 엔티티의 모든 요소를 수정하는것을 벌크성 수정 쿼리라 한다.

쿼리가 적용되는 요소가 2개이상인 경우를 말한다,

 

순수 JPA에서의 벌크 연산

Repository

public int bulkAgePlus(int age){

 return em.createQuery(

 "update Member m set m.age = m.age +1" +

 " where m.age >= :age")

.setParameter("age" , age)

.excuteUpdate()

//excuteUpdate는 최종적으로 연산이 적용된 데이터의 갯수가 나온다.

}

 

데이터 JPA 벌크연산

Repository

@Modifying //update 시엔 이 값을 꼭 넣어야 한다, 없으면 에러가 발생

@Query(update Member m set m.age = m.age +1 where m.age >= :age)

int bulkAgePlus(@Param ("age") int age)

 

벌크연산에는 문제가 있는데

JPA는 영속성 컨테이너에서 엔티티들을 관리하고 있는데

이때 벌크여산은 영속성을 무시하고 DB에 바로 쿼리를 적용시켜버린다.

그럼 영속화 되기 전 Data와 영속성 관리중인 데이터간에 불일치가 발생할 수 있다.

 

만약
int resultCount = memberRepository.bulkAgePlus(20);

//DB에 벌크연산을 진행

 

List<Member> result = memberRepository.findByUsername("member5")

Member member5 = result.get(0)

//그런데 find는 영속성 에서 값을 찾아온다.

위 벌크연산이 적용된건DB 뿐이라 영속성엔 벌크연산이 적용되지 않은 데이터가 반환된다.

 

그래서 해결법은

1.같은 @Transaction 인 service 에서 

2.@Persistence Context

EntityManager entityManager 영속성 컨테이너를 호출

3.벌크 연산이 실행된 후 영속성 컨테이너를 비워준다.

int resultCount = memberRepository.bulkAgePlus(20);

entityManager.clear()

entityManager.flush()

//벌크연산 후 영속성 컨테이너를 초기화 해준다.

4.find때 영속성에 값이 없어서 DB 에서 값을 가져온다.

 

JPA에선 Update후 flush 후 실행해야 한다.

 

데이터 JPA에서는 em.clear()할 필요가 없다 ,

Repository에서 

@Modifying(clearautomatically = true) 

// 이 옵션이 있으면 벌크연산후 자동으로 em.clear를 해준다.

@Query("update Member m set m.age = m.age +1 where m.age >= :age")

int bulkAgePlus(@Param ("age") int age)