Spring
- 순환 참조 해결을 위한 고민의 타임라인
1. 하나의 Repository에는 여러 서비스가 접근하지 않는 것이 좋다.(관련된 도메인의 서비스만 접근하고 다른 서비스에서 해당 Repository에 접근하기 위해서는 서비스 계층을 거치게끔 하라.)
2. PostService와 CommentService의 순환 참조 발생
(PostService 입장 - 포스트가 삭제될 때 관련된 모든 댓글을 삭제하고 싶다.)
(CommentService 입장 - "/api/{postId}" 라는 uri로 댓글 생성 요청이 오는데 이 때 오는 postId에 대한 검증 + postId로 받아온 post로 comment 엔티티를 생성하고 싶다.)
2-1. 사실 여기서 아주 쉽게 해결이 가능했다. -> CommentService에서 PostService 참조 안하면 그만. 애초에 프론트에서 없는 postId로 요청이 올 리도 없고 + comment 엔티티에도 postId만 존재하므로 post 자체가 필요가 없음.
3. 과연 1. 이 진리인가?
어느 고수분께서는 1. 이 계층적 구조를 명확하고 안전하게 하는 데에는 좋다고 하셨지만, 나와 같이 순환 참조가 발생할 위험이 있으므로 다른 도메인 Repository를 참조하는 것도 취향 차이지 나쁜 건 아니다. -> 이것도 아주 간편한 해결책 그냥 Repository 직빵으로 참조하면 끝
4. cascade란 옵션을 사용해라!
나는 기존에 PostService에서 Post를 찾아오고 이 Post에 대한 모든 댓글들을 찾은 후 삭제하는 방식을 채택했다.
그러나 연관관계 설정하는 @OneToMany에 cascade의 remove 옵션을 걸어주면 Post 삭제 시 연관관계를 맺은 모든 엔티티가 삭제된다.
5. 엇 근데 사실 현업에서는....
현업에서는 데이터를 아예 삭제하는 경우는 없다고 한다. -> 이것도 뭐 상황에 따라 다르지만..
데이터를 백업해놓거나 삭제처리에 대한 필드값을 두고 업데이트만 해준다고 한다.
여기서 Hard Delete와 Soft Delete라는 개념도 나오는데 완전히 삭제냐 아니냐의 개념이다.
6. 그럼 어떡하라고 ㅠㅠ
백업은 생각할 양이 너무 방대해지는 것 같고 필드값만 고려해보자면
엔티티에 @SQLDelete 라는 어노테이션을 통해 Delete 쿼리가 발생할 때 자신이 정의한 특정 쿼리로 바꿔서 실행시켜준다고 한다. -> 여기서 delete(entity)가 아닌 삭제처리 필드값을 set하게끔
여기에 @Where 이라는 어노테이션으로 삭제처리가 되지 않은 엔티티만 조회할 수 있게 해주면 된다고 한다.
이러면 쿼리를 직접 쏘는 것이기 때문에 CommentRepository에 접근할 필요가 없다. -> 이럴 거면 양방향 연관관계 끊고 직접 쿼리?
그리고 @Where는 내가 삭제처리한 데이터를 조회조차 할 수 없기 때문에 현업에서는 사용이 힘들다고 한다.
그래서 만약에 삭제된 데이터를 조회해야 한다면 @Where 보다는 1.JPQL을 이용하거나 어플리케이션 레벨에서 제어해주기
2. @FilterDef, @Filter를 활용하여 특정 엔티티 매니저 세션에 대해서만 필터를 정의하기 가 존재한다.
7. 일단 기능 구현이 우선!
이런 고민들 끝에 3으로 돌아가 일단 PostService가 CommentRepository를 참조하게 했다. 일단 모든 기능 구현을 마친 후에 고민해보고 글로 남기면 매우 좋을 것 같다.
알고리즘
- 프로그래머스 : 큰 수 만들기(Level 2, 그리디)
느낀 점
너무 춥다.
'TIL' 카테고리의 다른 글
[23.12.26] (0) | 2023.12.26 |
---|---|
[23.12.21] (1) | 2023.12.22 |
[23.12.19] (1) | 2023.12.19 |
[23.12.18] (0) | 2023.12.18 |
[23.12.15] (1) | 2023.12.15 |