일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스프링 롬복
- ubuntu
- 우테코
- @Modifying
- 스프링부트배포
- 밤랩
- clearAutomatically
- Mock
- @Query
- 검색api
- 자바 롬복
- bomblab
- SpringDataJPA
- 우아한테크코스
- BDDMockito
- 벌크연산
- docker에 ubuntu
- jpa
- ubuntu이미지
- 회고
- 영속성컨텍스트
- NonUniqueResultException
- 우아한테크코스5기
- 우아한테크코스 블랙잭
- Argos
- 배포스크립트
- 우분투
- unique result
- 레벨인터뷰
- @Param
- Today
- Total
Jeomxon's Tech Note
[Spring-Data-Jpa] 벌크연산 시 주의해야할 점(Update, Delete등) 본문
spring-data-jpa에서 벌크연산을 처리할 때 주의해야할 사항은 꼭 알아둬야할 것 같아서 포스팅을 한다.
@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
위 코드에서 파라미터로 들어온 age보다 크거나 같은 age에 대해서는 1을 더하여 update쿼리를 날려주는 것을 알 수 있다.
첫번째 주의사항은 @Modifying을 써줘야한다는 것이다.
@Modifying을 쓰지 않으니깐 이런 경고문이 뜬다. update 혹은 delete쿼리를 보낼 때는 반드시 필요한 어노테이션임을 알 수 있다.
두번째 주의사항은 벌크연산 후 영속성 컨텍스트를 초기화 시켜줘야한다는 것이다.
위와 같은 상황이라고 가정했을 때 처음 내가 한명의 멤버에 대해서 age를 40이라고 지정해줬다.
memberRepository.save(new Member("member5", 40));
그리고 멤버 전체에 대해서 벌크연산을 진행한 후 영속성 컨텍스트에서 해당 멤버를 가져오게되면 어떻게 될까?
int resultCount = memberRepository.bulkAgePlus(20); //벌크 연산
List<Member> result = memberRepository.findByUsername("member5");
Member member5 = result.get(0);
System.out.println("member5 = " + member5);
이처럼 멤버의 age는 40으로 나온다. 분명이 Update쿼리가 날라가서 41이 됐을텐데 왜 40이 나올까?
바로 영속성 컨텍스트에서 가져왔기 때문이다.
정리하자면 벌크연산을 할 때 Update쿼리를 날리면 영속성 컨텍스트가 아니라 db에 값이 바로 update된다.
즉 영속성 컨텍스트를 거치지 않는다는 의미이다.
그 후 find를 통해서 영속성 컨텍스트에 있는 동일한 멤버를 가져오게 되면 당연히 벌크연산이 들어가기 전의 값을 가진 멤버를 반환한다.
따라서 벌크연산 이후에는 영속성 컨텍스트를 초기화 시켜줘야한다.
int resultCount = memberRepository.bulkAgePlus(20);
em.flush();
em.clear(); //영속성 컨텍스트 초기화
List<Member> result = memberRepository.findByUsername("member5");
Member member5 = result.get(0);
System.out.println("member5 = " + member5);
위와 같이 영속성 컨텍스트를 초기화한 후 다시 member를 가져오면 어떻게 되는지 확인해보자.
이렇게 find를 통해 가져오면 db에서 가져와서 영속성 컨텍스트에 올려놓고 객체로 넘겨서 가져온다.
영속성 컨텍스트를 초기화 한 후 다시 조회를 하면 db와 일치하는 값을 얻을 수 있다.
따라서 벌크연산 후에는 항상 영속성 컨텍스트를 초기화하자!
하지만 이렇게 매번 clear를 신경써서 하기 귀찮고 까먹을 수도 있을거라 생각했는지 spring-data-jpa에서는 추가적인 기능을 제공한다.
@Modifying(clearAutomatically = true) //Modifying에 옵션부여
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
@Modifying에 clearAutomatically옵션을 true로 주면 항상 연산 후에 자동으로 영속성 컨텍스트를 초기화해준다.
위와 같이 사용하는 것이 가장 편하고 실용적일 것이다.
'Spring > JPA' 카테고리의 다른 글
[Spring-Data-JPA] @Query의 장점, 그리고 연관된 JPQL의 단점 (0) | 2022.08.03 |
---|