inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

자바 ORM 표준 JPA 프로그래밍 - 기본편

영속성 컨텍스트 에러 질문

325

dlsvmfjsrnrmf

작성한 질문수 1

0

안녕하세요 스프링 부트 환경에서 JPA 를 쓸때 이해하지 못하는 에러가 나서 질문합니다.

현재 서비스와 레포지토리 레이어를 분리해서 사용하고 있고, @Transactional 어노테이션은 레포지토리 클래스에만 적용해 놓은 상태입니다.

우선 save 함수와 findOne 함수는 이런식으로 존재합니다.

public void save(Lost entity) 
{em.persist(entity);}

public Optional<Lost> findOne(Long id) 
{return Optional.ofNullable(em.find(Lost.class, id));}

Lost 엔티티는 이런식으로 존재합니다 (더 많은 컬럼이 있지만 필요한 것만 적었씁니다)

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "lost")
@Entity
@JsonIgnoreProperties({"organization", "postCodeType"})
public class Lost {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lost_id")
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "lost_user_id", referencedColumnName = "user_id", insertable = false, updatable = false)
    @EqualsAndHashCode.Exclude
    @ToString.Exclude
    private User user;
}

근데 서비스 레이어에서

Lost result = lostsRepository.save(LostMapper.INSTANCE.toEntity(lostRequest));

System.out.println(lostsRepository.findOne(result.getId()).get().getUser());

이런식으로 findOne을 해서 user 필드를 가져오려고 하면 null 이 뜹니다ㅠㅠ

@ManyToOne(fetch = FetchType.EAGER)

이 설정도 잘 해줬고, 커밋도 레퍼지토리에서 해서 그러면 user 필드가 채워져서 와야 할텐데 이해가 안됩니다..ㅠ @ToString.Exclude 문제는 아닌게 getUser 을 해서 봤을때도 null 이 뜹니다. 혹시 뭐가 문제일까요? findOne을 쓰는 다른 곳에서는 잘 동작하는데, 저렇게 save 를 한 직후에 save 한 엔티티 아이디로 findOne을 하면 조인한 다른 객체가 null로 뜹니다.

 

추가로 우선 해당문제는

public void save(Lost entity) 
{em.persist(entity);
em.flush();
em.refresh(entity);
}

이런식으로 바꿔서 해결했습니다.

메커니즘이 이해가 안가서 질문드립니다!!

감사합니다

java jpa

답변 1

1

인프런 AI 인턴

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

영속성 컨텍스트 에러는 JPA 에서 관리하는 엔티티 객체와 데이터베이스의 데이터가 일치하지 않아서 발생할 수 있습니다. 이 경우, 엔티티 객체를 수정한 후 트랜잭션을 커밋하기 전에 데이터베이스에서 변경된 값을 가져오는 경우 에러가 발생할 수 있습니다.

보통 이런 경우, EntityManager에서 detach() 메서드를 사용해 엔티티 객체를 영속성 컨텍스트에서 분리시킴으로써 해결할 수 있습니다. 또는 EntityManager의 flush() 메서드를 사용해 영속성 컨텍스트에 있는 엔티티 정보를 데이터베이스와 일치시켜 에러를 방지할 수 있습니다.

해당 코드를 보면 @Transactional 어노테이션이 레포지토리 클래스에만 적용되어 있기 때문에, 서비스 레이어에서 트랜잭션 처리가 되지 않아서 영속성 컨텍스트 에러가 발생한 것 같습니다. 서비스 레이어에서 @Transactional 어노테이션을 추가해주시면 문제가 해결될 수 있을 것 같습니다.

또는 EntityManager를 이용해 분리시켜주거나 flush() 메서드를 사용해 엔티티 정보를 데이터베이스와 일치시켜줄 수도 있습니다. 하지만 이 방법은 트랜잭션 범위를 벗어나기 때문에 추천하지 않습니다.

참고로, 해당 코드에서는 UserRepository를 참조하지 않기 때문에 쿼리스트링을 작성해 User 엔티티 정보를 가져올 수도 있습니다.

자세한 내용은 스프링 공식 문서나 구글 검색을 통해 확인해보시길 바랍니다. 감사합니다!

벌크연산에서 member.getAge 호출 시 영속성 컨텍스트에서 데이터를 가져오는건가요?

0

24

2

inheritance startegy 선택시 고려사항

0

22

1

Entity 동등성 비교

0

18

1

실무 조언 관련 질문입니다.

0

46

1

H2데이터베이스 파일 생성

0

56

2

서브쿼리 강의에서 ALL 예시 관련 질문드립니다.

0

52

2

수정또는 삭제시 영속성 엔티티에 값이 무조건 있어야 하나요?

0

52

1

JPQL 메소드와 락

0

55

1

Delivery @OneToOne

0

60

1

17강 4~5분대 테이블 값 조회가 안됩니다.

0

93

2

UnsupportedOperationException 발생

0

86

3

H2 Database 연결이 안됩니다.

0

92

2

연관관계 매핑 질문드립니다.

0

85

2

h2데이터베이스 실행오류

0

107

2

persistence.xml

0

106

2

양방향 연관관계에서 연관관계의 주인(mappedBy)을 왜 꼭 정해야 하나요?

0

80

1

영속성 컨텍스트

0

65

1

JPA 프록시

0

95

1

Native Query와 MyBatis

0

68

1

영속성 컨텍스트는 어떤 메모리에 저장되는건가요?

0

85

1

임베디드 타입 예시 코드 관련 질문

0

114

3

명시적 조인에서 별칭을 주면 왜 객체에 접근할 수 있나요

0

94

3

인텔리제이 패키지 커서 단축키 질문

0

108

2

혹시 현재는 ID 데이터 타입이 String이면 안되나요?

0

144

1