JPA 벌크연산이란

여러건의 데이터를 한번에 수정하는 것이다.
JPA에선 executeUpdate()을 사용해서 연산하고
Spring data JPA를 이용하여 JPQL을 사용할땐 @Modifying을 update @Query에 붙여 사용한다.

EntityManager manager;

String sql = "update member m set m.money = m.money + 1000 where m.money <= :money";
int count = manager.createQuery(sql)
                    .setParameter("money", 1000)
                    .executeUpdate();


@Modufying
@Query("update member m set m.money = m.money + 1000 where m.money <= :money")
int bulkMoneyUp(@Param("money) int money)


JPQL을 사용했을때 데이터가 안맞는 이유는?

@Modufying
@Query("update member m set m.money = m.money + 1000 where m.money <= :money")
int bulkMoneyUp(@Param("money) int money)

memberRepository.save(new Member("member1, 2000"));
memberRepository.save(new Member("member2, 1000"));
memberRepository.save(new Member("member3, 1000"));

int count = memberRepository.bulkMoneyUp(1000);

다음과 같은 상황에서 memeber1, 2, 3의 money는 얼마일까.
찍어보면 각 2000, 1000, 1000 일 것이다.
물론 db에는 1000씩 플러스가 되어있겠지만 저 상황에서 member들의 money는 기존과 같을 것이다.

이유는 영속성 컨텍스트에 있다.
jpa에서 save()를 이용할땐 영속성 컨텍스트도 함께 업데이트가 되지만 JPQL의 벌크연산을 사용하면 영속성 컨텍스트를 무시하고 db에 바로 연산을 요청한다.
그래서 영속성 컨텍스트의 값은 변경이 안된 것이다.

이를 해결하려면 영속성 컨텍스트를 날려버려야한다.

@PersistenceContext
EntityManager manager;

@Modufying
@Query("update member m set m.money = m.money + 1000 where m.money <= :money")
int bulkMoneyUp(@Param("money) int money)

memberRepository.save(new Member("member1, 2000"));
memberRepository.save(new Member("member2, 1000"));
memberRepository.save(new Member("member3, 1000"));

int count = memberRepository.bulkMoneyUp(1000);

manager.clear();

clear()를 사용하여 영속성 컨텍스트를 날려버리거나 아니면

@Modufying(clearAutomatically = true)
@Query("update member m set m.money = m.money + 1000 where m.money <= :money")
int bulkMoneyUp(@Param("money) int money)

memberRepository.save(new Member("member1, 2000"));
memberRepository.save(new Member("member2, 1000"));
memberRepository.save(new Member("member3, 1000"));

int count = memberRepository.bulkMoneyUp(1000);

@Modufying(clearAutomatically = true) 를 사용하여 영속성을 비워주면 된다.