본문으로 바로가기

사이드 프로젝트 도중 JPA 영속 컨텍스트(Persistence Context) 객체 결과값이 제대로 나오지 않았다.. JPA는 회사내 기술스택이기도 해서 기능 개발에 치우치다보니 공부가 부족했었다 ㅠㅠ 이것저것 구글링해보니 변경 감지(Dirty Checking)와 연관이 있었는데 살펴보다가 JPA 쿼리 실행 프로세스에 대해서도 볼수있었다.

 

실제 마주쳤던 코드를 한번 살펴보자

@Transactional(propagation = Propagation.REQUIRED)
public void applyChallenge(Long memberId, ChallengeRequest.ApplyChallenge request) {
	// begin
    Member member = memberApplicationService.findById(memberId);
    Challenge challenge = challengeJpaRepository.findById(request.getChallengeId())
    	.orElseThrow(ChallengeNotFoundException::new);

	// setting
    ChallengeMember challengeMember = challenge.apply(member);

	// execute
    challengeMemberJpaRepository.save(challengeMember);
	
    // result print
	System.out.println(challenge.getChallengeMembers().size());
}

간략하게 설명하면, Challenge에 신청하는 Member(ChallengeMember)를 추가하는 메소드이다. 

@Transactional로 영속성 컨텍스트가 관리하도록 하고(객체가 같은 참조값을 바라보고 있다? 정도로 생각하면 됌)

save 메소드를 호출하면서 기존에 조회했던 challenge.getChallengeMembers size가 +1 될거라고 예상했지만...

challenge 객체값은 변경되지 않았다.

 

결론적으로 내가 간과했던건 save 시점에 내부적으로는 flush(sql 쿼리 실행) => commit(DB 동기화) 처리가 된다는 것이다. commit으로인해 트랜잭션이 종료되면서 challenge 객체는 영속성 컨텍스트 관리에서 벗어나게된다.

 

수정 코드는 아래와 같다.

@Transactional(propagation = Propagation.REQUIRED)
public void applyChallenge(Long memberId, ChallengeRequest.ApplyChallenge request) {
	// begin
    Member member = memberApplicationService.findById(memberId);
    Challenge challenge = challengeJpaRepository.findById(request.getChallengeId())
    	.orElseThrow(ChallengeNotFoundException::new);

	// setting
    ChallengeMember challengeMember = challenge.apply(member);

	// execute
    // challengeMemberJpaRepository.save(challengeMember);
	
    challenge.getChallengeMembers().add(challengeMember); // 객체 데이터 변경으로 Dirty Checking 처리
    
    // result print
	System.out.println(challenge.getChallengeMembers().size()); // 데이터 사이즈 +1
}

 

참고 링크 : https://www.popit.kr/jpa-%EB%B3%80%EA%B2%BD-%EA%B0%90%EC%A7%80%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0/