JPA

[JPA] [Trouble Shooting] 에러 Cannot delete or update a parent row: a foreign key constraint fails 참조 무결성 제약 조건 ON DELETE CASCADE

뚜코맨 2024. 4. 13. 00:35

글 작성을 한 후, 댓글이 달려있는 상태에서 글 삭제 테스트를 하던 중 

 

이런 에러를 보았다.

더보기

Cannot delete or update a parent row: a foreign key constraint fails 

(`learningmate`.`tb_reply`, CONSTRAINT `FKsxgehpxyljiiatkcutvuahw13` FOREIGN KEY (`board_no`) 

REFERENCES `tb_board` (`board_no`))

 

일단 에러가 발생한 이유는

✓ 데이터 삭제 시 해당 테이블에 연관관계가 설정 되어 있기 때문에 부모를 삭제 할 경우 부모 엔티티를 참조하는 자식 엔티티가 불안정한 상태가 되어 사전에 방지해주기 위해 에러가 발생하는 것이다.

 

Trouble Shooting! 

에러를 해결 하기 위해서는 ON DELETE CASCADE 제약조건을 걸어주는 것이다.

(ON DELETE CASCADE: 외래키로 연결되어 있는 데이터들이 일관성을 유지할 수 있기 위해 매핑이 되어 있는 데이터를 삭제할 때 부모, 자식의 데이터까지 한번에 삭제 시켜주는 옵션이다.)

 

ON DELETE CASCADE 제약 조건을 JPA 환경에서 적용하는 방법을 알아보자.

 

- Reply(엔티티)

 

현재 댓글 엔티티에서 @ManyToOne(다대일) 매핑이 되어있고, 그 아래 @OnDelete(....)를 넣어주는 것이다. 

 

- Board(엔티티)

 

그 후 부모 엔티티인 보드 엔티티에서 @OneToMany(....) 선언하고, 고아 객체 제거 옵션을 넣어준다.

- orphanRemoval = true 옵션: 부모 엔티티가 삭제되면 자식 엔티티도 삭제 되게 해주는 옵션이다.

고아객체제거란?

JPA에서는 부모엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제해주는 기능을 제공해준다. 이를 고아 객체 제거(ORPHAN) 라고 한다. 마치 가비지컬렉션처럼 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 판단하여 삭제하는 기능이다. 즉 한곳에서 참조하는 @OneToMany 나 @OneToOne 일때에만 사용한다. 그래서 해당 다중성에만 속성을 제공한다.

 

현재 Board와 Reply의 연간관계는 아래와 같다.

- @OneToMany가 부모, @ManyToOne이 자식이다.

- 부모는 여러 자식을 가질 수 있고, 자식은 하나의 부모를 가지는 1:N 관계이다.

ex)게시물(부모)은 여러 댓글(자식)을 가질 수 있고, 댓글(자식)은 하나의 게시글(부모)를 가지고 있다.

 

💡 결론

영속성 전이와 고아 객체

- JPA는 엔티티 매니저의 persist와 remove 메서드를 통해 영속성을 관리한다. 그래서 부모 엔티티에 CASCADE ALL과 고아객체 제거를 true로 해두면 이는 곧 자식의 생명주기를 부모가 관리한다는 뜻이다.