Springboot

JPA CascadeType 종류와 부모 테이블 삭제

25G 2023. 8. 16. 19:17

Cascade?

Cascade는 사전적의미로 종속, 계산식 폭포 등의 의미를 품고 있다. 이름에서 알수 있듯이 db 관계를 맺고 있는 테이블끼리 cascade를 한다는건 상위 테이블을 삭제하면 관계맺은 하위 테이블 까지 튜플이 같이 삭제된다는 뜻이 된다.

PersistentObjectException: detached entity passed to persist

위 에러는 JPA 사용시 자동으로 생성되는 값을 가진 필드에 직접 값을 할당해 저장하고자 할때 발생되는 에러이다.

JPA 에서의 Cascade

JPA 라는 ORM 에서 Cascade는 다음과 같은 타입과 종류가 있습니다.

javax.persistence.CascadeType

JPA Cascade Type

  • ALL
    • 상위엔티티에서 하위 엔티티로 모든작업 전파 (모든 Cascade설정을 적용하겠단뜻)
  • PERSIST
    • 하위 엔티티까지 영속성 전달
  • MERGE
    • 하위 엔티티까지 병합 작업을 지속
    • 트랜잭션이 종료되고 detach 상태에서 연관 엔티티를 추가하거나 변경된 이후에 부모 엔티티가 merge를 수행하게 되면 변경사항이 적용된다.
  • REMOVE
    • 하위 엔티티까지 제거작업을 지속 즉 삭제시 연관된 엔티티도 같이 삭제된다.
  • REFRESH
    • 데이터베이스로부터 인스턴스 값을 다시 읽어오기 (새로고침)
  • DETACH
    • 영속성 컨텍스트에서 엔티티 제거
    • 부모 엔티티가 detach() 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.
  • RESIST
    • 엔티티를 생성하고, 연관 엔티티를 추가하였을 때 persist() 를 수행하면 연관 엔티티도 함께 persist()가 수행된다. 만약 연관 엔티티가 DB에 등록된 키값을 가지고 있다면 detached entity passed to persist Exception이 발생한다.

종속된 테이블 데이터를 제거하는 방법은 없을까?

OnDelete 과 OnUpdate

위 두가지 방법이 있습니다 해당설정을 달아주면 테이블 스키마가 생성될때 다음과같은 ddl 스키마 로그가 남습니다.

  • alter table 자식테이블명 add constraint FK8lyvvv9ln92lfhl5gegfxqbo8 foreign key (폴인키명) references 부모테이블명 (id) on delete cascade

하지만 이방법은 그리 좋은 방식이 아닙니다. 왜냐하면 제가 생각하기에 프로그램상에 원치않은 관계맺은테이블의 변화를 야기하기때문인것 같습니다.
그리고 자료를 더 찾아보다가 존경하는 김영한님의 다음과 같은 피드벡글을 읽고 많은 공부가 됐습니다.(감사합니다)

다음은 인프런 질문과 답변에 답변을 해주신 내용입니다.

이 경우 OnDelete, OnUpdate같은 방법을 사용하는 것은 오히려 복잡해지고, 좋지 않은 방법입니다.

JPA는 객제지향 스타일로 개발 하는 것이 원칙입니다. 따라서 부모 엔티티를 삭제하기 전에 자식 엔티티를 찾고, 부모 엔티티와 연관관계를 null 처리 하는 것이 맞습니다.

만약 성능이 고민된다면, 배치 update JPQL(객체지향 쿼리 언어2 - 벌크 연산 참고)을 사용해서 한번에 해당 부모와 관련있는 모든 자식 엔티티의 부모 FK 값을 null로 변경하면 됩니다.

감사합니다.