728x90
일반적으로는 Entity에 대한 수정사항은 변경감지를 통해서 진행됩니다. 하지만 여러 Entity에 대해서 update를 한 번에 처리해야하는 경우도 있습니다.
@Repository
public interface MemberJpaRepository extends JpaRepository<Member, Long> {
int addTokens(@Param("name") String name, @Param("amount") Integer amount);
}
select 쿼리와 달리 update 쿼리는 2가지를 신경써야 합니다.
1. @Modifying annotation을 추가해주어야 합니다.
2. Update 쿼리는 DB에 직접 호출됩니다.
@Modifying가 없으면 테스트 코드 작성과정에서 검증될 가능성이 높기 때문에 큰 문제가 되지 않습니다. 두 번째 사항은 뒤늦게 발견되고 장애로 이어질 수 있습니다.
Update 쿼리는 DB에 직접 호출됩니다. 그래서 현재 트랜잭션에서 관리하는 영속성 컨텍스트에는 update 사항이 반영되지 않습니다. 따라서 영속성 컨테스트와 데이터베이스에 있는 데이터 사이에 불일치가 발생합니다.
이를 피하기 위해서는 EntityManager#flush(), EntityManager#clear()를 update 쿼리 이후에 호출해주어야 합니다.
@Test
public void addToken() {
//given
String name = "name";
String email = "email";
Member member = new Member(name, email, "pwd");
memberJpaRepository.save(member);
int updatedCount = memberJpaRepository.addTokens("name", 10);
Assertions.assertThat(member.getToken()).isEqualTo(10);
em.flush();
em.clear();
}
이것을 보다 편리하게 적용하는 방법은 아래와 같습니다
@Repository
public interface MemberJpaRepository extends JpaRepository<Member, Long> {
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("update Member m set m.token = m.token + :amount where m.name = :name ")
int addTokens(@Param("name") String name, @Param("amount") Integer amount);
}
728x90
'DEV > Spring Data JPA' 카테고리의 다른 글
QueryHint를 적용하기 전에 고려해볼 사항 (0) | 2023.09.24 |
---|---|
@EntityGraph로 fetch join 쉽게 쓰기 (0) | 2023.09.24 |
Page<Entity>를 API의 응답으로 리턴하는 방법 (0) | 2023.09.24 |
Join과 Pagination 함께 사용할 때 Count 쿼리 최적화 (0) | 2023.09.24 |
COUNT 쿼리, Page<T> vs Slice<T> (0) | 2023.09.24 |