본 포스트는 김영한 님의 실전! 스프링 데이터 JPA 강의를 토대로 작성하였습니다.
이전 포스트에 이어 마지막! 쿼리 메소드 기능을 총 정리해보자.
벌크성 수정 쿼리란, 같은 로직을 많은 값들에 적용하는 것이다.
ex) 새해가 되었으니 회원들 나이를 1살씩 올리자!
//순수 JPA의 벌크 연산
public int bulkAgePlus(int age) {
int resultCount = em.createQuery(
"update Member m set m.age = m.age + 1" +
"where m.age >= :age")
.setParameter("age", age)
.executeUpdate();
return resultCount;
}
기존에 JPQL을 이용하여 벌크 연산을 수행하려면 다음과 같이 작성하면 된다. 이를 스프링 데이터 JPA를 사용하는 코드로 바꿔보자.
@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
@Query는 기존과 동일하다. 바뀐 것은 @Modifying이 붙는다는 점이다.
단 벌크 연산을 할 때는 주의할 점이 있는데, 바로 영속성 컨텍스트를 이용하지 않는다는 것이다.
따라서 벌크 연산을 한 뒤 해당 값들이 바뀌었다고 기대하고 또 다른 로직을 수행하더라도 한 트랜잭션 안에서 영속 컨텍스트에 이미 값이 들어가 있는 경우 1차 캐시에서 값을 가져오기 때문에 벌크 연산을 하기 이전 값을 가져오게 된다.
따라서 보통 벌크 연산을 수행한 뒤 em.flush(), em.clear()를 호출하여 영속성 컨텍스트를 모두 비우기를 추천한다. 또한 @Modifying(clearAutomatically = true)
요런 식으로 벌크 연산 후 자동으로 영속성 컨텍스트를 비우는 옵션을 줄 수도 있다.
JPA에서 연관된 엔티티를 미리 가져오고 싶다면 fetch join을 사용했었다. @EntityGraph는 fetch join의 간편 버전이라 생각하면 된다. 사용법은 다음과 같다.
//공통 메서드 오버라이드
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
//JPQL + 엔티티 그래프
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
//메서드 이름으로 쿼리에서 특히 편리하다.
@EntityGraph(attributePaths = {"team"})
List<Member> findByUsername(String username)
간단하다! 어노테이션을 붙이고 attributePaths에 같이 가져오고자 하는 연관된 필드 이름을 적으면 된다. 즉 Member Entity에 현재 team 이라는 필드명으로 Team 객체를 들고 있으므로 값에 team을 적어주면 된다.