DevKim

[Data JPA] 벌크성 수정쿼리, @EntityGraph 본문

JPA

[Data JPA] 벌크성 수정쿼리, @EntityGraph

on_doing 2021. 7. 1. 18:03
728x90

[ 벌크성 수정 쿼리 ]

- 모든 멤버의 나이를 1씩 증가시켜줘 ! 할때 쿼리 한번으로 쭉 1씩 더해주는게 효율적일 때 벌크연산을 한다.

 

※ 주의 ※

벌크성 수정,삭제 쿼리는 @Modifying 어노테이션을 꼭 넣어주어야하고,

만약 벌크 쿼리를 날린 후, 다시 조회해야한다면 꼭!! 영속성 컨텍스트를 초기화 해주어야한다.

 

** 벌크 연산은 영속성 컨텍스트를 무시하고 직빵으로 DB에 반영하기 때문에,

영속성 컨텍스트에 있는 엔티티의 상태와 DB에 있는 엔티티의 상태가 달라질 수 있다. **

 

※ 권장 방안 ※

1. 영속성 컨텍스트를 clear해준 후 엔티티가 없는 상태에서 벌크 연산을 먼저 수행한다.

2. 부득이하게 영속성 컨텍스트에 엔티티가 있으면, 벌크 연산 직후 영속성 컨텍스트를 초기화한다.

-> @Modifying(clearAutomatically = true)

 

벌크 연산도 JPQL이므로 어차피 실행직전에 자동으로 flush가 실행되므로 flush는 수동으로 해주지 않아도 된다.

 

Interface

@Modifying(clearAutomatically = true)
@Query("update Member m set m.age=m.age+1 where m.age>=:age")
int bulkAgePlus(@Param("age") int age);

Test

@Test
public void bulk() throws Exception{
    //given
    memberRepository.save(new Member("mwmber1", 10));
    memberRepository.save(new Member("mwmber2", 10));
    memberRepository.save(new Member("mwmber3", 20));
    memberRepository.save(new Member("mwmber4", 30));
    memberRepository.save(new Member("mwmber5", 40));

    //when
    int resultCount = memberRepository.bulkAgePlus(20);

    //then
    assertThat(resultCount).isEqualTo(3);

}

[ @EntityGraph ]

: 지연로딩으로 설정했는데, 한꺼번에 조회해야할 때 연관된 엔티티들을 한번에 조회하는 방법

 

*member와 team은 지연로딩 관계일 때, 만약 team의 데이터를 조회한다면

조회할 때마다 쿼리가 실행되는 N+1 문제가 발생한다.*

 

-> @EntityGraph는 사실상 페치 조인의 간편 버전이다.

 

기존엔 연관된 엔티티를 한번에 조회하기 위해선, fetch join 이 필요했다.

@Query("select m from Member m left join fetch m.team")
List<Member> findMemberFetchJoin();

이렇게되면 member을 조회하면 연관된 team을 한방 쿼리로 모두 끌고온다.

이때는 물론 프록시 객체가 아닌 진짜 객체를 들고온다.


@EntityGraph를 사용해보자

 

1. 만약 member 모두를 조회하고 싶은데, team도 모두 함께 조회하고 싶다면

findAll을 override 해버리고 EntityGraph를 추가해주면된다.

@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();

2. Query도 짜고 싶은데 페치 조인만 추가하고 싶을 땐,

쿼리 작성 후 위에 EntityGraph 살포시..

@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();

3. 메소드 이름 쿼리도 쓰고 싶은데 페치 조인 추가하고 싶을 땐 제일 간편하다.

@EntityGraph(attributePaths = {"team"})
List<Member> findByUsername(String username);

사실 복잡한 쿼리에선 JPQL로 페치 조인 짜는게 사용하는게 더 일반적이라고 한다.

간단한 쿼리에서 사용하면 간편할 것 같다.

728x90
Comments