여태까지는 데이터를 직접 삭제하는 방법을 사용해왔다.
데이터를 직접 삭제하는 방법에는 Hard Delete 가 있다.
그런데 Soft Delete라는 방법을 알게되었다.
그리고 Hard Delete가 데이터를 관리하는 차원에서 더 좋은 방법이라고 한다.
그래서 Soft Delete에대해 더 알아보았다.
여러 블로그를 참고하고 생각해본 결과 필자도 Soft Delete가 더 좋다는 의견에 동의한다.
왜냐하면 Review를 남긴 User가 회원을 탈퇴한다고 하면, 그 Review도 삭제되어야 하는가? 라는식의 질문을 해봤을때
User가 남긴 Review는 남아있어야 데이터 관리 차원에서, 그리고 사업자 입장에서도 좋기 때문이다.
이제 Hard Delete를 Soft Delete로 바꾸어 보자.
구현방법은 생각보다 간단했다.
BaseEntity에 deletedAt으로 null값으로 초기화하여 soft delete를 할 수있게 하였다.
@Getter
@Setter
@MappedSuperclass //BaseEntity를 상속한 entity들은 BaseEntity의 멤버변수를 모두 컬럼으로 인식
@EntityListeners(AuditingEntityListener.class) //entity를 DB에 적용 전후로 콜백(auditing 정보를 주입하는 클래스)
@ToString
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
private LocalDateTime lastModifiedAt;
private LocalDateTime deletedAt;
// 삭제
public void deleteSoftly(LocalDateTime deletedAt) {
this.deletedAt = deletedAt;
}
// 확인
public boolean isSoftDeleted() {
return null != deletedAt;
}
// 삭제 취소
public void undoDeletion(){
this.deletedAt = null;
}
}
@Where 어노테이션을 클래스에 주어서 해당 엔티티가 쿼리문으로 실행될때 where조건이 포함된 쿼리가 실행되게 하였다.
그리고 @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)에서
cascade = CascadeType.ALL, orphanRemoval = true를 빼주었다.
ascadeType.REMOVE는 부모 엔티티가 삭제되면 자식 엔티티도 삭제되기 때문이다.
(하지만 우리는 Soft Delete를 구현할 것이기 떄문에 직접적인 상관은 없다.)
//where 이외에 어노테이션은 넣지 않았다.
@Where(clause = "deleted_at is null")
public class Post extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String body;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id") //DB에 해당 명으로 컬럼설정
private User user;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Like> likes = new ArrayList<>();
}
이제 Service에서 로직은 변경해 보자
해당 클래스에 @Transactional어노테이션이 적용되어있다.
public PostResponse delete(Long postId, String userName) {
//작성자와 게시글 에러 체크
checkUserNPost(postId, userName);
//softDelete 구현
Post post = postRepository.findById(postId).orElseThrow(()->
new AppException(ErrorCode.POST_NOT_FOUND, ErrorCode.POST_NOT_FOUND.getMessage()
));
post.deleteSoftly(LocalDateTime.now());
return PostResponse.of("포스트 삭제 완료", postId);
}
이제 잘 적용이 된것을 확인할 수 있다.