인프런 커뮤니티 질문&답변

램쥐뱅님의 프로필 이미지
램쥐뱅

작성한 질문수

실전! Querydsl

스프링 데이터 JPA 리포지토리로 변경

영속성 콘텍스트의 범위.

해결된 질문

작성

·

321

0

=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (/아니오)

[질문 내용]
안녕하세요.

영속성콘텍스트에 영속화된 Entity 로 생각이 드는데도 불구하고 영속성 콘텍스트가 아니고 쿼리의 호출결과로 데이터를 얻어오는 부분이 있어서 질문을 드립니다.

테스트 코드는 아래와 같습니다.

참고: boardId = boardEntity @Id

@Transactional
public BoardDto updateBoard(Integer boardId, String title) {
  jBoardEntity entity = jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne();
  entity.updateTitle(title);
  entityManagerFactory.getPersistenceUnitUtil().isLoaded(entity) // true
  return jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne();
}

에서 처음 selectFrom 때 select 쿼리후 entity 정상반환하여 영속회되고 update title 문까지 정상동작합니다.

이후 영속성 콘텍스트에 로드가 됐다는걸 확인해보았고 동일한 ID 의 entity 를 조회했을때는 영속성 컨텍스트에서 제공되길 기대했으나 console 로그에는 sql 이 나가는 것으로 보아 실제 db 에 sql 이 작동한것으로 보입니다.

혹시 제가 놓친 부분이있다면 말씀해주시면 감사하겠습니다.

답변 2

1

램쥐뱅님의 프로필 이미지
램쥐뱅
질문자

잘정리된 글을 발견하여 올립니다

답변감사합니다

https://cheese10yun.github.io/jpa-jpql/

0

안녕하세요, 인프런 AI 인턴이에요.

영속성 컨텍스트의 범위에 대해 궁금하신 것 같네요. 영속성 컨텍스트는 엔티티를 관리하고, 변경 사항을 추적하며, 데이터베이스와의 상호 작용을 관리하는 역할을 합니다.

보통 영속성 컨텍스트는 트랜잭션 범위 내에서 동작하며, 트랜잭션이 종료될 때 함께 종료됩니다. 따라서 영속성 컨텍스트는 트랜잭션당 하나의 범위를 가지게 됩니다.

하지만 코드를 보면, updateBoard 메서드 안에서 selectFrom 하는 시점에 영속성 컨텍스트가 이미 존재하고 있는 것 같습니다. 그리고 updateTitle 메서드를 호출하여 엔티티의 상태를 변경한 후, 다시 selectFrom하여 같은 엔티티를 가져옵니다.

이 경우, 이미 영속성 컨텍스트에 존재하는 엔티티가 업데이트되는 것이므로, 영속성 컨텍스트에서 찾아보는 동작은 발생하지 않습니다. 대신 쿼리를 실행하여 새로운 결과를 가져올 것입니다.

영속성 컨텍스트는 엔티티를 식별자(보통은 기본 키)를 통해 추적하므로, 엔티티가 변경되지 않은 경우에는 쿼리를 실행하지 않고 영속성 컨텍스트에 있는 엔티티를 반환하게됩니다. 따라서 여러분이 기대하는 것과는 조금 다른 결과가 나타날 수 있습니다.

이를 해결하기 위해서는 영속성 컨텍스트에 있는 엔티티를 제거하고 다시 쿼리를 실행하는 방법을 사용할 수 있습니다. entityManager.clear() 메서드를 호출하면 현재 영속성 컨텍스트의 내용이 초기화되고, 다음 쿼리 실행 시 새로운 결과를 가져오게 됩니다.

영속성 컨텍스트와 관련한 깊은 이해가 필요한 부분이기 때문에, 더 자세한 내용을 알고 싶으시다면 관련된 책이나 강의를 참고하는 것이 좋을 것 같습니다. 질문 주셔서 감사합니다.

램쥐뱅님의 프로필 이미지
램쥐뱅
질문자

수정된 질문을 올리겠습니다.

우선 코드부터 작성해보면

@Transactional
public BoardDto updateBoard(Integer boardId, String title) {
  BoardEntity entity = jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne();
  entityManagerFactory.getPersistenceUnitUtil().isLoaded(entity) // true
  return jpaQueryFactory.selectFrom(boardEntity).where(boardEntity.baordId.eq(boardId)).fetchOne();
}

update 부분만 제거하였습니다.

첫번째 selectFrom (db 에 실제 select 문이 실행됨) 으로 부터 얻어온 entity가 영속화 된걸 동일하게 isLoaded 로 확인하였습니다.

문제는 이후 다시 selectFrom 으로 return 받을때는 영속화된 객체를 그대로 줄것으로 예상했으나 console 에는 db에 실제 select 문이 실행되는것으로 확인하였습니다.

결과적으로는 select 문이 2번 실행되는것을 확인하였습니다.

해당 결과에 대해서 놓친부분이 있다면 말씀해주시면 감사하겠습니다.

램쥐뱅님의 프로필 이미지
램쥐뱅

작성한 질문수

질문하기