org.hibernate.TransientObjectException: persistent instance references an unsaved transient instance of 'jpabook1.jpashop1.domain.Member' (save the transient instance before flushing)
에러 원인
JPA를 활용해서 Entity를 만들고 주문로직을 구현하는 중이었다.
회원Entity, 주문상품Entity, 수량 정보를 가지고 주문Entity를 생성할 때 오류가 발생했다.
TransientObjectException 오류는 Fk값이 없는 MemberEntity(DB에 저장되지 않은)를 OrderEntity에 저장하려고 해서 발생한 에러였다.
@Entity
@Table(name="orders")
@Getter @Setter
public class Order {
// 생략 ~~~
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
// 생략 ~~
}
분명 나는 findById 메서드를 통해서 member Entity를 가져 왔는데 뭐가 문제지 하고 계속 헤매다가
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
OrderEntity와 생성과 삭제를 같이하는 cascade 옵션을 추가하기에 이르렀다.
하지만 이도 틀렸다. 같이 생성되는 신규 엔티티 였으면 이게 맞았을 텐데 진짜 원인은
자 여기 연관관계 편의 메서드라고 정의한 나의 코드에 오류가 있었다
내가 전달한 member를 사용하는게 아니라 계속 신규
Entity를 생성해서 저장하려고 하니까 에러가 발생한 것이 었다.
member를 전달하고 나서도 new Member();라니 반성해야겠다. InteliJ 자동 완성이 너무 편해서 저런 실수가 발생했다.
결국에는 코드를 원래대로 고치고 돌리니 잘 동작한다.
정리
1. TransientObjectException 오류는 DB저장되지 않은 Entity를 FK로 활용해서 발생하는 에러다.(Order테이블을 생성하기 위한 Member)
2. 결국 에러의 원인은 내가 작성한 코드 실수 였다.
3. cascade 옵션에 대해서 한번 보자.
CascadeType.RESIST
– 엔티티를 생성하고, 연관 엔티티를 추가하였을 때 persist() 를 수행하면 연관 엔티티도 함께 persist()가 수행된다. 만약 연관 엔티티가 DB에 등록된 키값을 가지고 있다면 detached entity passed to persist Exception이 발생한다.
CascadeType.MERGE
– 트랜잭션이 종료되고 detach 상태에서 연관 엔티티를 추가하거나 변경된 이후에 부모 엔티티가 merge()를 수행하게 되면 변경사항이 적용된다.(연관 엔티티의 추가 및 수정 모두 반영됨)
CascadeType.REMOVE
– 삭제 시 연관된 엔티티도 같이 삭제됨
CascadeType.DETACH
– 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.
CascadeType.ALL
– 모든 Cascade 적용
출처: https://cpdev.tistory.com/85 [하루하나:티스토리]
4. CascadeType.All 로 해결하려고 했는데 이는 완전 잘못된 접근이었다. 앞으로도 오류를 완전히 이해하고 코드를 작성하자.
'JPA' 카테고리의 다른 글
실전! 스프링 데이터 JPA 강의 정리 (0) | 2025.02.12 |
---|---|
실전! 스프링 부트와 JPA 활용1 강의 정리 (0) | 2025.02.05 |
JPA 양방향 연관관계의 주인 (0) | 2025.02.01 |
JPA (2) | 2025.02.01 |