Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags more
Archives
Today
Total
관리 메뉴

seaking110 님의 블로그

JPA를 이용한 일정관리 프로그램 트러블 슈팅 본문

Today I Learned

JPA를 이용한 일정관리 프로그램 트러블 슈팅

seaking110 2025. 2. 13. 13:47

 

트러블 슈팅

 

1. 단방향 연관 관계에서 부모 삭제 시 삭제가 되지 않는 문제


문제 상황

 

회원(Member)을 삭제할 때 해당 회원이 작성한 할 일이 존재하면 삭제되지 않는 문제 발생!!

  • 기존에는 단방향 연관관계로 설정
  • 회원을 삭제하려고 하면 연관된 Todo가 존재하므로 DB의 외래 키 제약 조건으로 인해 삭제가 불가능

문제점

  • Member 삭제 시, Todo가 함께 삭제되지 않음
  • 외래 키 제약 조건으로 인해 SQL 오류 발생
  • 할 일을 수동으로 삭제하지 않으면 회원 삭제 불가능

💡 해결 방법 고민

방법 1 : 양방향 연관관계로 변경 및 JPA의 cascade = CascadeType.ALL 및 orphanRemoval = true 사용

@Entity
public class Member {
    @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Todo> todos = new ArrayList<>();
}
  • 처음엔 단방향 연관관계에서 cascade = CascadeType.ALL 및 orphanRemoval = true 를 사용했는데 적용이 되지 않았다!
    • 안되는 이유!!
    • 단방향 연관관계 (Todo → Member) 로 설정하면, Member 엔티티에는 Todo에 대한 정보를 전혀 알지 못함.
    • "이 회원이 어떤 할 일을 가지고 있는지" 를 JPA가 알 수 없기 때문에 자동 삭제가 불가능함.
  • 양방향 연관관계로 변경 

장점

✔ Member 삭제 시 연관된 Todo도 자동으로 삭제됨
명시적으로 todoRepository.delete()를 호출할 필요 없음 → 코드 간결화
✔ orphanRemoval = true 덕분에 리스트에서 제거하면 DB에서도 자동 삭제

 

단점

❌ Member 엔티티가 Todo 엔티티를 관리해야 해서 양방향 연관관계 설정이 필요함


 

방법 2 : DB의 on delete cascade 설정

FOREIGN KEY (member_id) REFERENCES member(id) ON DELETE CASCADE;

장점

DB 차원에서 자동 삭제 → JPA 설정 없이도 적용 가능
✔ SQL에서 직접 처리하므로 성능이 더 좋을 수도 있음

 

단점

❌ DB에서만 처리하므로 JPA 영속성 컨텍스트와 동기화되지 않을 수도 있음

❌ JPA에서 삭제 로직을 직접 제어할 수 없음

 


📌  최종 결정

방법 1 : 양방향 연관관계로 변경 및 JPA의 cascade = CascadeType.ALL 및 orphanRemoval = true 사용

  1. JPA에서 자동으로 연관된 Todo 삭제 가능 → 코드 단순화
  2. 방법 2를 사용할 시 JPA로 제어하기 어려운 큰 문제  발생
  3. 확장성 & 유지보수 용이

 

 

 

 

 

 

 

2.  필터의 ResponseStatusException이 적용되지 않는 문제 발생


문제 상황

 

회ㅍ

필터의 ResponseStatusException이 적용되지 않는 문제 발생

  • 로그인 여부를 확인하는 필터를 구현하여, 로그인하지 않은 사용자는 401 Unauthorized 에러를 반환하도록 설정
  • 하지만 예상했던 401 에러가 아닌 500 서버 에러 발생

 문제점

  • 필터에서 ResponseStatusException을 던짐 → 500 Internal Server Error 발생
  • ResponseStatusException은 Spring MVC (@RestController) 내부에서만 자동 처리됨
  • 서블릿 필터에서는 Spring 예외 처리 메커니즘이 적용되지 않음 → 예외 미처리로 500 발생

💡 해결 방법 고민

방법 1 : HttpServletResponse.sendError() 사용

if (session == null || session.getAttribute(Const.LOGIN_MEMBER) == null) {
    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "로그인이 필요합니다.");
    return;
}
  • 처음엔 단방향 연관관계에서 cascade = CascadeType.ALL 및 orphanRemoval = true 를 사용했는데 적용이 되지 않았다!
    • 안되는 이유!!
    • 단방향 연관관계 (Todo → Member) 로 설정하면, Member 엔티티에는 Todo에 대한 정보를 전혀 알지 못함.
    • "이 회원이 어떤 할 일을 가지고 있는지" 를 JPA가 알 수 없기 때문에 자동 삭제가 불가능함.
  • 양방향 연관관계로 변경 

장점

✔ Spring 기본 예외 처리(BasicErrorController)를 활용할 수 있음
✔ Spring MVC와의 자연스러운 연동 가능

 

단점

❌ sendError()를 사용하면 Spring이 HTML로 에러 페이지를 반환할 수도 있음


 

방법 2 : HttpServletResponse.setStatus() + getWriter().write() 사용

if (session == null || session.getAttribute(Const.LOGIN_MEMBER) == null) {
    httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
    httpResponse.getWriter().write("please login first");
    return;
}

장점

Spring MVC 예외 처리와 관계없이 401 응답을 직접 반환 가능
추가적인 설정 없이 바로 적용 가능

 

단점

❌ Spring의 예외 처리 체인을 활용하지 못함


📌  최종 결정

방법 2 : HttpServletResponse.setStatus() + getWriter().write() 사용

  1. 가장 직접적으로 401 Unauthorized 응답을 반환할 수 있음
  2. Spring 예외 처리 없이도 모든 요청에 대해 일관성 유지 가능
  3. 메시지를 함께 반환하여 프론트엔드에서 쉽게 처리 가능

 

'Today I Learned' 카테고리의 다른 글

[Git] Conventional Commits에 대해  (0) 2025.02.18
테이블 설계와 정규화  (0) 2025.02.17
JPA  (0) 2025.02.10
JPA 꿀팁  (0) 2025.02.10
일정 관리 피드백  (0) 2025.02.07