프로젝트 기간이 끝난지도 벌써 2주가 다 되어간다 ~
시간이 정말 빠르다... 하지만 아직 완성되지 않은 우리의 프로젝트 (🔒조금 답답하다)
해결해야 할 부분이 정말 많아 보이는데 보완해야 할 부분이 아니라 완성해야 할 부분이기에 팀원들 모두 힘을 모아 해야 한다.🥲 다들 두 달 내내 잠도 제대로 못 자고 달렸으니 힘든 것은 이해한다.. 조금만 더 힘내자구우!
노션에 정리해 둔 우리가 아직 구현하지 못한 기능 구현 리스트 !
구현하고 내가 구현한 부분들은 다 수정을 했기에 지웠다. 그리고 제발 보안 쪽을 빨리 수정하고싶다.
오늘은 User 탈퇴 시 게시글, 댓글, 대댓글까지 삭제하는 기능을 추가하고 게시글 삭제 시 댓글, 대댓글 삭제하는 기능까지도 추가했다. << 이 과정에서 무결성 제약조건을 위반하는 사례들이 발생했다.
오늘 정처기 공부하면서 무결성 제약조건을 봤는데 반가웠다.
🚨 문제 발생 / Caused by: java.sql.SQLIntegrityConstraintViolationException
Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`StudyGround_db`.`Answer`, CONSTRAINT `FKqggcfke5o6wpxd23s5usgnv49` FOREIGN KEY (`member_Id`) REFERENCES `Member` (`memberId`))
에러 메세지를 살펴보았더니 "부모 행을 delete 하거나 update 할 수 없다. 외래 키 제약 조건 (참조 무결성) 으로 인한 실패" 라고 적혀 있었다.
🔻 참조 무결성
FK 는 NULL 이거나 참조하는 기본키의 값과 동일해야 한다.
그리고 메세지에서는 "DB의 Answer 테이블을 참조, Answer 테이블의 member_id 가 Member 테이블의 memberId의 외래키로 참조" 되어있다고 나와있었다.
원래 내가 작성한 Member 엔티티는 다음과 같았다.
Member Entity
@Getter
@Setter
@RequiredArgsConstructor
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
private String email;
private String name; // 닉네임
private String phone;
private String password;
private String profileImage;
@ElementCollection(fetch = FetchType.EAGER)
private List<String> roles = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Board> boardList;
@JsonIgnore
@OneToMany(mappedBy = "member")
private List<Bookmark> Bookmarks;
}
Cascade를 사용하기 전 Member에서 Answer와 Comment를 조회하거나 관리하는 것이 없었기에 Member 엔티티에서 @OneToMany 관계를 설정해주지 않았다. 그리고 이것이 문제가 된 것이었다.
게시글 작성 후 삭제 하는 것은 Test를 통과했는데 Answer를 작성하고 Member를 삭제 하려니 삭제가 안 되고 오류 메세지가 계속 나는 것이다. 이 때 당연 Member 입장에서는 Member가 참조하지 않는 값이 작성되어 있는데 Member를 삭제 하려고 하니 삭제가 되지 않고 에러가 발생되는 "참조 무결성" 오류가 발생 되는 것이었다.
Answer Entity
@Entity
@Getter
@Setter
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long answerId;
@Column(length = 10000, nullable = false)
private String content;
@Column
private LocalDateTime modifiedAt = LocalDateTime.now();
@JoinColumn(name = "board_Id")
@JsonIgnore
@ManyToOne
private Board board;
@JoinColumn(name = "member_Id")
@JsonIgnore
@ManyToOne
private Member member;
@OneToMany(mappedBy = "answer", cascade = CascadeType.ALL)
private List<Comment> comments;
}
🗝️ 문제 해결 방법
처음에는 에러메세지를 구글링 하여 해결 방법을 찾으려고 하였으나 무결성의 종류에 따라 에러의 종류도 다양했고 에러의 해결 방법 또한 다양했다. 그래서 "참조 무결성" 의 특징을 생각하며 에러를 스스로 해결하고자 하였다.
Member에서 자신이 참조하지 않는 값을 참조함으로써 삭제가 불가하고 있다. << 는 것에 초점을 두니 바로 해결 방법이 생각 났다. Member에 Answer를 참조 시켜주면 되는 것이었다. 이와 마찬가지로 Comment 또한 참조 시켜줌으로써 문제를 해결할 수 있었다 !
수정한 Member Entity
@Getter
@Setter
@RequiredArgsConstructor
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
private String email;
private String name; // 닉네임
private String phone;
private String password;
private String profileImage;
@ElementCollection(fetch = FetchType.EAGER)
private List<String> roles = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Board> boardList;
@JsonIgnore
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Answer> answerList;
@JsonIgnore
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> commentList;
@JsonIgnore
@OneToMany(mappedBy = "member")
private List<Bookmark> Bookmarks;
}
💬 느낀 점
오류 메세지가 명확하게 나와서 금방 찾을 수 있었던 것 같다. 또한, 오늘 정처기 공부를 하면서 마주했던 내용이기에 더욱 잘 기억에 남을 수 있을 것 같기도하다 핫 : ) 이렇게 해결이 될 때 마다 뭔가 너무 뿌듯하고 기분 좋은 해결이다~
오늘 만난 문제와는 다른 이야기이지만 CascadeType과 어떨 때 어떤 것을 사용하는지에 대해 조금 더 정확히 알고싶다. 항상 REMOVAL 또는 ALL 만 사용하게 되는 것 같은데 다른 타입에 대해서도 정리를 해보는 시간을 가져야겠다.