a foreign key constraint fails가 났을 때 부모와 자식 중 어디를 봐야 하는지
문제 발생
비슷해 보이는 두 오류가 다른 상황에서 났습니다.
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails원인 분석
두 오류는 방향이 반대입니다.
1452 (ER_NO_REFERENCED_ROW_2) — 자식 행을 넣거나 고치려는데 가리키는 부모 행이 없습니다. 존재하지 않는 post_id로 댓글을 만들려는 경우입니다.
1451 (ER_ROW_IS_REFERENCED_2) — 부모 행을 지우거나 고치려는데 그 행을 가리키는 자식이 남아 있습니다. 댓글이 달린 글을 지우려는 경우입니다.
그래서 고칠 곳이 다릅니다. 1452는 부모를 먼저 만들거나 자식이 가리키는 값을 고쳐야 하고, 1451은 자식을 먼저 정리하거나 참조 동작을 바꿔야 합니다.
이 오류가 났다는 것은 대개 애플리케이션이 순서를 어겼거나, 삭제 정책을 정하지 않았다는 뜻입니다. 제약 자체는 데이터가 서로 어긋나지 않게 지켜 준 것입니다.
해결 방안
- 1452는 삽입 순서를 봅니다. 트랜잭션 안에서 부모를 먼저 만들고 그 id로 자식을 만듭니다. 일괄 import라면 부모 테이블을 먼저 채웁니다.
- 폼에서 온 부모 id는 실제로 존재하는지 확인합니다. FK 제약이 막아 주기는 하지만, 그 결과는 사용자에게 보여 줄 수 없는 DB 오류입니다. 경계에서 조회해 확인하면 알맞은 메시지를 줄 수 있습니다. 이 저장소도 폼에서 온 id를 도메인 조회로 한 번 더 확인합니다.
- 1451은 삭제 정책을 스키마에 적습니다. 코드에서 순서를 챙기는 대신 제약이 표현하게 합니다.
| 정책 | 의미 | 쓰는 곳 |
|---|---|---|
ON DELETE CASCADE | 부모가 지워지면 자식도 함께 | 좋아요·북마크처럼 부모 없이 의미가 없는 데이터 |
ON DELETE SET NULL | 자식의 FK를 NULL로 | 작성자가 탈퇴해도 글은 남겨야 할 때 |
ON DELETE RESTRICT | 자식이 있으면 삭제 금지 | 지워지면 안 되는 참조 |
이 저장소는 사용자 삭제 시 게시글의 작성자를 SET NULL로 두어 글을 남기고, 좋아요·북마크는 CASCADE로 함께 지웁니다 — 데이터의 성격이 다르기 때문입니다.
- 소프트 삭제와 FK를 함께 쓸 때 주의합니다.
deleted_at만 채우는 방식은 행이 남아 있으므로 FK 오류가 나지 않습니다. 대신 조회에서deleted_at IS NULL을 빠뜨리면 지운 데이터가 되살아납니다. - 테스트 데이터 정리 순서를 맞춥니다. 통합 테스트에서 자주 만나는 오류입니다. 만든 역순으로 지우거나, 애초에 CASCADE가 걸린 부모만 지우면 됩니다.
SHOW CREATE TABLE로 실제 제약을 확인합니다. 오류 메시지의 뒷부분에 제약 이름과 관련 컬럼이 붙어 나오므로, 어느 FK인지 특정할 수 있습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.