BackEnd/JPA

[JPA] 영속성 연관관계 전이 CASCADE 란?

hyunki.Dev 2022. 11. 13. 23:26

JPA를 공부하면서 항상 헷갈렸던 부분이라 명확하게 정리를 해보고 넘어가려 합니다.

 

CASCADE

- 영속성 연관관계의 전이를 의미합니다.  

- 부모 엔티티에서 자식 엔티티로 상태를 전이하는 것입니다.

ex. 부모 엔티티 저장할 때 자식 엔티티도 함께 저장, 게시글과 첨부파일

- Parent와 Child가 라이프사이클이 동일할 때, Child를 소유하는 Parent가 하나일 때 사용하는 것이 좋습니다.

 

Entity의 상태

  • Transient : JPA가 모르는 상태 (단순 객체 생성)
  • Persistent : JPA가 관리중인 상태 (1차 캐시, Dirty Checking, Write Behind, ...)
  • Detached : JPA가 더이상 관리하지 않는 상태
  • Removed : JPA가 관리하긴 하지만 삭제하기로 한 상태

 

# CascadeType

ALL 

  • 엔티티의 모든 상태 전이
  • 모든 CASCADE 옵션 적용
  • 모든 작업을 부모에서 자식 엔티티로 전파

PERSIST

  • 엔티티 persiste(영속) 전이
  • 엔티티를 영속화 할 때 연관된 엔티티도 함께 유지
  • Transient 인스턴스를 Persistent로 만들어줌

REMOVE - 엔티티를 삭제할 때 연관된 엔티티도 함께 삭제 전이

MERGE - merge 전이
REFRESH - refresh 전이
DETACH - detach 전이

 

 

부모 엔티티 에서 자식엔티티의 내용을 저장할 때 CASCADE.PERSIST 옵션이 없으면

자식 엔티티에는 해당 내용이 저장되지 않을 수 있다. 

 

 

[Hibernate ORM 6.0.0 User Guide 예제 코드]

@Entity
public class Person {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL)
    private List<Phone> phones = new ArrayList<>();

    //Getters and setters are omitted for brevity

    public void addPhone(Phone phone) {
        this.phones.add(phone);
        phone.setOwner(this);
    }
}


@Entity
public class Phone {

    @Id
    private Long id;

    @Column(name = "`number`")
    private String number;

    @ManyToOne(fetch = FetchType.LAZY)
    private Person owner;

    //Getters and setters are omitted for brevity
}

https://docs.jboss.org/hibernate/orm/6.0/userguide/html_single/Hibernate_User_Guide.html#pc-cascade

 

Hibernate ORM 6.0.2.Final User Guide

Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat

docs.jboss.org

 

 

고아 객체

  •  부모 엔티티와 연관관계가 끊어진 자식 엔티티 자동으로 삭제합니다.
  •  orphanRemoval = true 로 옵션을 줍니다. 
  •  JPA에서는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능 제공
    •  연관되어 있는 자식 엔티티의 id 에 대하여 delete 쿼리문이 수행됩니다.
  •  참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제
  •  때문에 참조하는 객체가 하나일 때만 사용해야 함 (특정 엔티티에서만 소유하고 있는 엔티티)
  •  @OneToOne, @OneToMany 에서만 사용 가능

 

@Entity(name = "Person")
public static class Person {

	@Id
	@GeneratedValue
	private Long id;

	@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
	private List<Phone> phones = new ArrayList<>();

	//Getters and setters are omitted for brevity

	public void addPhone(Phone phone) {
		phones.add(phone);
		phone.setPerson(this);
	}

	public void removePhone(Phone phone) {
		phones.remove(phone);
		phone.setPerson(null);
	}
}

@Entity(name = "Phone")
public static class Phone {

	@Id
	@GeneratedValue
	private Long id;

	@NaturalId
	@Column(name = "`number`", unique = true)
	private String number;

	@ManyToOne
	private Person person;

	//Getters and setters are omitted for brevity

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		Phone phone = (Phone) o;
		return Objects.equals(number, phone.number);
	}

	@Override
	public int hashCode() {
		return Objects.hash(number);
	}
}

 

cascade = CascadeType.ALL + orpahnRemoval = true

- 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식 엔티티의 생명주기 관리 가능

- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용

- 부모 엔티티 삭제 시 자식 엔티티들도 삭제

 

cascade = CascadeType.ALL, cascade = CascadeType.REMOVE

- 부모 엔티티 삭제 시 자식 엔티티들도 삭제됨

- orpahnRemoval=true 없어도 연관관계 상태(삭제)까지 전파됨

- orpahnRemoval=true 없으므로 부모 엔티티에서 가져온 자식 엔티티 리스트에서 remove할 경우 자식 엔티티가 삭제되는건 아님!

 

cascade = CascadeType.PERSIST

- 부모 엔티티 삭제 시 부모 엔티티만 삭제

- 부모 자식을 바라보는 자식 엔티티가 있을 경우 FK 제약이 때문에 에러 발생

ERROR: Referential integrity constraint violation: "FKLH67J1N7X7GT59U0PBKWQH6O6: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (CAST(1 AS BIGINT))"; SQL statement:

 

cascade = CascadeType.PERSIST + orpahnRemoval = true

- 부모 엔티티 삭제 시 자식 엔티티들도 삭제됨

- orpahnRemoval=true 있어야 자식 삭제됨

 

 

참고: 

https://newwisdom.tistory.com/72

 

[JPA] Cascade 간단 노트

2021-07-08글 JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다. 부모 엔티티를 영속 상태로 만들 때 연관된 자식도 한번에 영속 상태로 만들 수 있다. Cascade란? 영속성 전이 연

newwisdom.tistory.com

https://allonsyit.tistory.com/108

 

[JPA] 연관관계 영속성 전이 CASCADE

# CASCADE - 부모 엔티티에서 자식 엔티티로 상태를 전이하는 것 ex. 부모 엔티티 저장할 때 자식 엔티티도 함께 저장, 게시글과 첨부파일 - Parent와 Child가 라이프사이클이 동일할 때, Child를 소유하

allonsyit.tistory.com