@Test
void readAllUserBoard_로그인_하고_조회하였지만_결과가_있는_경우() {
// given
// when
boardService.createBoard(BoardCreateRequestDto.builder()
.boardName("boardName2")
.boardColor("boardColor2")
.boardInfo("boardInfo2")
.build());
List<BoardReadAllResponseDto> result = boardService.readAllUserBoard();
// then
assertThat(result.size()).isEqualTo(1);
}
Lazy Initialization
JPA에서는 연관된 엔터티를 로딩하는 전략 중 LAZY 전략을 선택할 수 있다.
이 전략은 해당 엔터티에 실제로 접근될 때까지 데이터를 로딩하지 않는다.
그러나 트랜잭션 범위 밖에서 LAZY 전략으로 로딩된 엔터티에 접근하려고 하면 LazyInitializationException
이 발생하게 된다.
영속성 컨텍스트와 생명주기
영속성 컨텍스트는 엔터티의 생명주기를 관리하는 중요한 요소이다.
트랜잭션 범위 내에서 엔터티는 영속성 컨텍스트에 속하며 트랜잭션이 종료되면 이와 함께 영속성 컨텍스트도 종료된다.
createBoard 메서드의 문제
createBoard
메서드는 여러 데이터베이스 연산을 트랜잭션 범위 내에서 수행한다.
하나의 연산이 실패하면 다른 연산에 영향을 주며 데이터 불일치 문제가 발생할 수 있다. @Transactional
을 사용하면 모든 연산이 한 트랜잭션 범위 내에서 실행되므로 문제 발생 시 롤백이 가능해진다.
readAllUserBoard 메서드의 문제
readAllUserBoard
메서드에서 user.getBoards()
를 호출하면 연관된 Board
엔터티들을 가져온다.
트랜잭션 범위 밖에서 이를 실행하면 LazyInitializationException
이 발생할 위험이 있다.
그러나 @Transactional
을 사용하면 트랜잭션 범위 내에서 안전하게 접근할 수 있다.
@Test
@Transactional()
@Commit
void readAllUserBoard_로그인_하고_조회하였지만_결과가_있는_경우() {
// given
// when
boardService.createBoard(BoardCreateRequestDto.builder()
.boardName("boardName2")
.boardColor("boardColor2")
.boardInfo("boardInfo2")
.build());
List<BoardReadAllResponseDto> result = boardService.readAllUserBoard();
// then
assertThat(result.size()).isEqualTo(1);
}
createBoard에서 user에 영속성 연결을 통해 값을 수정해도 Test이기에 Save 내부의 @Transactional로 인해 DB반영되지 않고 영속성 컨테스트가 종료된다.
그 결과 readAllUserBoard에서 변경된 User을 조회하지 못하였던 것이다.
즉 @Transactional 어노테이션을 붙여 영속성 컨테스트를 확장하면 User 조회가 가능해져서 문제는 해결된다.