[JPA] JPA에서 update 하기

2024. 5. 3. 15:41카테고리 없음

1. Update 쿼리를 이용한 엔티티 수정

업데이트 쿼리를 이용해서 엔티티를 수정하는 방법은 간단해보입니다.

 

우선 Member 엔티티와 JPA 레포지토리를 생성합니다.

@Entity
@Getter
@Setter
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;

    private String nickname;
    
    ...
    
 }
public interface MemberRepository extends JpaRepository<Member, Long> {

    @Modifying
    @Query("UPDATE Member m SET m.nickname = :nickname where m.id = :id")
    int updateUserNickname(@Param(value="nickname") String nickname, @Param(value="id") Long id);
    
    ...
    
}

* 참고로 엔티티에서 @Setter는 테스트 코드 작성의 편의를 위해 작성했습니다.

 

어쨌든 위와 같이 회원(Member)의 닉네임을 바꾸는 쿼리를 JPQL을 이용해 작성했습니다.

 

그리고 아래와 같이 테스트 코드를 작성하고 실행시키면 어떤 결과가 나올까요?

updateMember 테스트코드


테스트코드 - 실패

결과를 보면, 테스트코드는 실패하는 것을 볼 수 있는데요.

 

그런데 아이러니하게 아래 사진과 같이 update 쿼리는 정상적으로 나가는 것을 볼 수 있습니다. 테스트코드가 실패한 이유는 무엇일까요?

update 쿼리는 정상적으로 나간다

 

정답은 영속성 컨텍스트에 있습니다.

 

update 쿼리는 영속성 컨텍스트에 저장된 캐시값을 변경하지 않은 채로 DB에 직접 쿼리를 날리게 되는데요.

 

그래서 실제 DB에 저장된 회원의 정보와 현재 영속성 컨텍스트에 남아있는 회원의 정보가 동기화되지 못합니다.

 

이 때, 테스트코드처럼 memberRepository.findById()를 통해 회원을 조회해오면 이전에 save()를 통해 저장했던 회원의 정보가 캐시로 남아있기 때문에 실제 DB의 값과는 달리 변경되지 않은 회원의 정보가 조회되는 것이죠.

 


이 문제를 해결하기 위해서는 아래와 같이 @Modifying(clearAutomatically = true) 옵션을 넣어줄 수 있습니다.

Modifying(clearAutomatically = true)

위처럼 clearAutomatically = true 옵션을 주게 되면 업데이트 쿼리를 날린 후에 영속성 컨텍스트를 자동으로 clear() 해주는데요.

 

따라서, 다시 테스트코드를 실행하게 되면 DB에서 회원 정보를 읽어온 후 영속성 컨텍스트에 저장하여 테스트가 성공하는 것을 볼 수 있습니다.