Spring Boot

[Spring JPA] @Where 어노테이션으로 인한 Foreign Key 제약 문제

ShinySinee 2024. 9. 12. 19:53

프로젝트에서는 처음에 하드 딜리트를 구현한 후, 나중에 소프트 딜리트로 업데이트하기로 계획했다. 어쩌다 보니 다른 팀원 분이 소프트 딜리트를 먼저 구현 한다 해서... deleted 필드 하나 추가 하니까 먼저 구현하고 있어도 괜찮을 거라 생각했다... 이것이 재앙의 시작이였다...ㅎㅎ허헣

1) 문제 발생

"could not execute statement [Cannot delete or update a parent row:
a foreign key constraint fails (`juinjang-db`.`limjang`, CONSTRAINT `FKjqr2spmi16ldk4bk5uvqkjj8r`
FOREIGN KEY (`member_id`) REFERENCES `member` (`member_id`))] 
[delete from member where member_id=?]; SQL [delete from member where member_id=?]; 
constraint [null]"}

며칠을 해도 계속 이 에러가 떴다..
limjang과 member 엔티티에 foreign키 에러이다. 이는 limjang에 무언가 삭제가 되지 않아 member 삭제 될 때 문제가 생긴 것이다.
그래서 하나씩 jpa 쿼리를 날려 지워주는 방법으로 바꾸어 주었다.

List<Limjang> limjangList = limjangRepository.findLimjangByMemberId(member.getMemberId());

for (Limjang limjang : limjangList) {
    scrapRepository.deleteByLimjangId(limjang);
    //체크리스트
    checklistAnswerRepository.deleteAllByLimjangId(limjang);
    //이미지
    imageRepository.deleteAllByLimjangId(limjang);
    //record
    recordRepository.deleteAllByLimjangId(limjang);
    //report
    reportRepository.deleteAllByLimjangId(limjang);
}

limjangRepository.deleteAllByMemberId(member);

 
 

Hibernate: select l1_0.limjang_id,l1_0.address,l1_0.address_detail,l1_0.created_at,l1_0.deleted,l1_0.price_id,l1_0.member_id,l1_0.memo,l1_0.nickname,l1_0.price_type,l1_0.property_type,l1_0.purpose,l1_0.record_count,l1_0.updated_at from limjang l1_0 where (l1_0.deleted = 0) and l1_0.member_id=?
select l1_0.limjang_id,l1_0.address,l1_0.address_detail,l1_0.created_at,l1_0.deleted,l1_0.price_id,l1_0.member_id,l1_0.memo,l1_0.nickname,l1_0.price_type,l1_0.property_type,l1_0.purpose,l1_0.record_count,l1_0.updated_at from limjang l1_0 where (l1_0.deleted = 0) and l1_0.member_id=?
select m1_0.member_id,m1_0.apple_sub,m1_0.created_at,m1_0.email,m1_0.image_url,m1_0.target_id,m1_0.nickname,m1_0.provider,m1_0.refresh_token,m1_0.refresh_token_expires_at,m1_0.updated_at from member m1_0 where m1_0.member_id=?
select ll1_0.member_id,ll1_0.limjang_id,ll1_0.address,ll1_0.address_detail,ll1_0.created_at,ll1_0.deleted,ll1_0.price_id,ll1_0.memo,ll1_0.nickname,ll1_0.price_type,ll1_0.property_type,ll1_0.purpose,ll1_0.record_count,ll1_0.updated_at from limjang ll1_0 where ll1_0.member_id=? and (ll1_0.deleted = 0) 
delete from member where member_id=?

 
그치만 이 방법도 위와 같은 쿼리문을 시행 후 똑같은 에러가 떴다.
로그를 잘 살펴보니 l1_o.deleted = 0이라는 조건이 추가 되어있었다. (추가한적이..없는데..?)
그래서 외래키를 가진 엔티티를 확인해보니

@Where 이라는 어노테이션이 있었다.
 

2) @Where 어노테이션

@Where 어노테이션은 엔티티의 기본 쿼리에 조건을 추가하는 데 사용된다. 이 어노테이션을 사용하면, 예를 들어, 특정 상태의 데이터만 조회하도록 제한할 수 있다.
예를 들어, @Where(clause = "deleted = false")라는 어노테이션이 붙어있다면, 해당 엔티티는 기본 쿼리에서 deleted 필드가 false인 데이터만 조회하게 된다.
이러한 조건은 엔티티를 필터링하기 위해 매우 유용하지만, 외래키를 가진 엔티티에서 삭제 연산을 시도할 때는 주의가 필요한다. 왜냐하면, @Where 어노테이션에 의해 조건이 자동으로 적용되기 때문에 예상치 못한 데이터 필터링이 발생할 수 있기 때문이다..

3) 원인

만약 자식 엔티티에 @Where 애너테이션이 적용되어 있고, deleted = false인 엔티티가 필터링된다면, 자식 엔티티가 삭제되도록 시도해도 @Where 필터에 의해 이 엔티티가 쿼리에서 제외될 수 있다.
결과적으로, 자식 엔티티가 제대로 삭제되지 않을 수 있다... 

이 문제를 해결한 후, 데이터가 정상적으로 삭제되는 것을 확인할 수 있다!!!!