Skip to main content Link Menu Expand (external link) Document Search Copy Copied

created at 2023-11-03

JPA 영속성 유지기간을 관찰하기 위한 여러 예제를 설명합니다

  1. @Transaction 코드 밖에서는 영속성 유지가 되지 않는 것을 확인
@Override
@Transactional("REQUIRED")
@Async("taskPool")
public CompletableFuture<UserCredential> saveUser(RegisterUserRequest req) {
    checkUserExistOrThrowCustomException(req.getUserId());
    UserCredential user = userCredentialRepository.save(req.toEntity());
    return CompletableFuture.completeFuture(user);
}

@Test
public void changeNameFunctionOutside(){
    userService.saveUser(req)
    .thenApply((user)->{
        user.setUserName("newUserName");
        return user;
    }).thenAccept((user)->{
        UserCredential findUser = userCredentialRepository.findById(user.getUserId()).orElseThrow(new RuntimeException());
        assertThat(findUser.getUserName()).isNotEqualTo("newUserName"); // oldUserName != newUserName 
})
}

  1. @Transaction 코드 내부에서 영속성 유지가 되는 것을 확인
@Override
@Transactional("REQUIRED")
@Async("taskPool")
public CompletableFuture<UserCredential> saveUser(RegisterUserRequest req) {
    checkUserExistOrThrowCustomException(req.getUserId());
    UserCredential user = userCredentialRepository.save(req.toEntity());
    return CompletableFuture.supplyAsync(()->{
        user.setUserName("newUserName"); // 내부로 변경
        return user;
    });
}

@Test
public void changeNameFunctionOutside(){
    userService.saveUser(req)
    .thenAccept((user)->{
        UserCredential findUser = userCredentialRepository.findById(user.getUserId()).orElseThrow(new RuntimeException());
        assertThat(findUser.getUserName()).isEqualTo("newUserName"); // oldUserName => newUserName == newUserName 
    })
}

이를 통해 바뀐 생각은 아래와 같아요.

  • 기존

Transaction은 ThreadLocal 하게 설정되며 @Transactional 로 설정 시, Thread 가 callback 함수를 호출하는 시점에 commit 되는 것으로 알고있었습니다. 즉, @Transactional 이 선언된 함수 내에서 thenApply 와 같은 callback 함수가 호출 되어도 엔티티는 Detached 된 상태이므로 변경되지 않을것이라고 판단했어요.

  • 변경

@Transactional 로 설정 시, 함수 가 Stack 에서 빠지는 시점에 commit 이 이루어지는것을 확인하였습니다. 즉, 함수 내부에서는 ThreadLocal 하다면 어떤 것이든 트랜잭션에 담길 것이고 외부에서는 Detached 된 엔티티를 반환받는것을 확인했어요.