1. Cascade 없이 직접 삭제하는 방식 (서비스 계층에서 처리)
구현 원리
- 양방향 매핑 없이
@ManyToOne
단방향 연관관계만 사용.
- 게시물(Board) 삭제 전에 댓글(Comment)과 좋아요(Like)를 서비스 계층에서 명시적으로 삭제.
엔터티 설정
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "board_id")
private Board board;
private String content;
}
@Entity
public class Like {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "board_id")
private Board board;
}
장점
- 단순한 단방향 연관관계(
@ManyToOne
만 사용)로 설계가 간단함.
- N+1 문제를 피할 수 있음: 불필요한 데이터 로딩이 없음.
- 연관된 엔터티를 서비스 계층에서 명시적으로 삭제하여, 제어가 용이함.
단점
- 데이터 삭제 로직을 서비스 계층에서 처리해야 하므로 코드가 복잡해질 수 있음.
- 댓글이나 좋아요가 많을 경우, 대량 삭제에 대한 성능 문제를 고려해야 함(필요 시 배치 처리 도입).
2. Cascade를 사용하는 방식 (양방향 매핑 활용)
구현 원리
@OneToMany
와 @ManyToOne
양방향 매핑 사용.
- 부모 엔터티(Board) 삭제 시 연관된 댓글과 좋아요도 자동 삭제 (
CascadeType.ALL
적용).
엔터티 설정
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Like> likes = new ArrayList<>();
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "board_id")
private Board board;
private String content;
}
@Entity
public class Like {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "board_id")
private Board board;
}
게시물 삭제 시 자동으로 연관 데이터 삭제
CascadeType.ALL
: 부모 엔터티가 삭제될 때 자식 엔터티(Comment, Like)도 함께 삭제됨.
orphanRemoval = true
: 부모와의 연관관계가 끊긴 자식 엔터티를 자동으로 삭제.
장점
- 삭제 로직이 간단해짐 : 부모 엔터티를 삭제하면 연관된 자식 엔터티도 자동으로 삭제됨.
- 코드가 서비스 계층에 비해 간결하고 직관적임.
단점
- 양방향 매핑으로 인한 N+1 문제가 발생할 수 있음.
- 데이터가 많을 경우 성능 저하가 발생할 수 있음.
- 양방향 연관관계로 인해 설계 복잡성이 증가함.
3. 비교 / Cascade 사용 vs 서비스 계층에서 직접 삭제
구분 |
Cascade 사용 |
서비스 계층에서 직접 삭제 |
연관관계 매핑 |
@OneToMany + @ManyToOne 양방향 매핑 필요 |
@ManyToOne 단방향 매핑만 사용 |
코드 복잡도 |
간단 (JPA가 자동으로 삭제 처리) |
서비스 계층에서 삭제 로직을 관리 |
N+1 문제 |
발생 가능 |
방지 가능 |
성능 |
많은 데이터 처리 시 성능 저하 가능 |
성능 최적화 용이 |
설계의 유연성 |
설계가 복잡해질 수 있음 |
설계가 단순하고 명확 |
4. 예상 발생 문제점
- N+1 문제 발생 시
- Cascade 방식을 사용할 경우, fetch 전략을 조정하거나 EntityGraph를 사용해 연관 데이터를 한 번에 로딩해야 합니다.
- 대량 데이터 삭제 성능 문제
- 직접 삭제 방식을 사용 시, 댓글이나 좋아요가 많을 경우 배치 쿼리나 JDBC Template을 활용해 성능을 개선할 수 있습니다.
- 삭제 시 참조 무결성 예외 발생
- 서비스 계층에서 댓글과 좋아요를 삭제할 때 외래키 제약조건에 의해 예외가 발생할 수 있으므로, 삭제 순서를 정확하게 관리해야 합니다.