[Spring boot] JPA Soft Delete 구현하기

Byuk_mm·2022년 10월 31일
3

Spring Boot Development

목록 보기
13/13
post-thumbnail

Spring Boot 개발 중 학습이 필요한 내용을 정리하고,
트러블 슈팅 과정을 기록하는 포스팅입니다.




✅ Background


지난 포스팅에서 JPA Delete 과정에서의 오류를 해결하고, JPA 영속성연관 관계를 고려하여 EntityDelete하는 작업에 관한 내용을 다뤘습니다. Delete 학습하던 중, DBDelete 작업은 Hard Delete, Soft Delete 이렇게 두가지로 나뉘는 것을 배울 수 있었습니다.

이번 포스팅에서는 Hard DeleteSoft Delete에 대해서 알아보고, Spring bootJPA를 활용하여 Soft Delete를 구현하는 작업에 관한 글을 작성하겠습니다.




✅ Hard Delete와 Soft Delete


📌 Hard Delete(물리 삭제)

  • SQLDELETE 명령어를 사용하여, 물리적으로 데이터를 삭제하는 방법입니다.
  • 실제로 디스크에서 데이터가 제거되기 때문에 디스크 공간을 확보할 수 있습니다.
  • 삭제된 데이터에 대해서 복원이 어렵습니다.
  • JPADeleteDefaultHard Delete입니다.

📌 Soft Delete(논리 삭제)

  • SQLUPDATE 명령어를 사용하여, FlagState 등의 삭제 여부를 알수 있는 컬럼을 추가하여 삭제 여부를 나타내는 방법입니다.
  • 물리적으로 데이터가 삭제되는 것이 아니기 때문에, 디스크 사용량이 증가합니다.
  • 조회 시 삭제 여부를 판단한 후, 조회되기 때문에 조회 성능이 저하될 수 있습니다. 또한 개발자의 부주의로 인해 삭제된 데이터가 조회될 수 있습니다.
  • 삭제 여부를 나타내는 칼럼의 변경만으로도 손 쉽게 변경할 수 있습니다.

📌 왜 Soft Delete를 구현하는가?

  • 삭제된 데이터를 활용해야하는 시점이 존재할 수 있습니다.
  • 물리적으로 삭제된 데이터는 복원이 어렵습니다.



✅ JPA Soft Delete


JPA를 활용한 Delete 작업을 구현하는 방법은 다음과 같이 3가지로 나눌 수 있습니다.

  1. 실제로 삭제(Hard Delete)
  2. 특정 값을 활용한 삭제 여부 표시(Soft Delete)
  3. 삭제된 값을 삭제 필드로 이동.

저는 2번째 방식을 채택하였고, deleted 라는 boolean형 타입의 칼럼을 추가해서 삭제여부를 표시했습니다. JPA의 어노테이션을 활용하면 이러한 Soft Delete를 손쉽게 구현 가능합니다.


📌 @SQLDelete

@Entity
@Table(name = "video_space")
@Getter
@SQLDelete(sql = "UPDATE video_space SET deleted = true WHERE video_space_id = ?")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class VideoSpace extends BaseEntity {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "video_space_id", updatable = false)
    private Long id;

	//.. 중략

첫 번째로 살펴볼 어노테이션은 @SQLDelete입니다. 해당 어노테이션은 Delete 쿼리가 발생할 때, 정의된 특정 쿼리로 바꿔서 실행시켜줍니다.

위의 예시로 해석해보자면 Delete 쿼리가 발생할때 delete = true Update 쿼리가 발생하도록 합니다.
해당 쿼리는 transaction이 종료되는 시점에 바껴서 나가게됩니다.

Hibernate: UPDATE video_space SET deleted = true WHERE video_space_id = ?

테스팅을 해보면, 실제로 위와 같이 delete 쿼리가 아닌 update 쿼리가 발생한 것을 확인할 수 있습니다.


📌 @Where

@Entity
@Table(name = "video_space")
@Getter
@SQLDelete(sql = "UPDATE video_space SET deleted = true WHERE video_space_id = ?")
@Where(clause = "deleted = false") // 추가
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class VideoSpace extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "video_space_id", updatable = false)
    private Long id;
    
    //.. 중략

두 번째로 살펴볼 어노테이션은 @Where입니다. 해당 어노테이션은 Select 쿼리가 발생할 때, 정의된 where 구문이 Default 옵션으로 추가돼서 실행됩니다.

즉 해당 EntitySelect하는 모든 Select 쿼리에 where deleted = false 구문이 추가되면서 삭제되지 않은 Entity만 조회될 수 있도록 합니다.

Hibernate: select ( .. 중략 .. ) where videospace0_.video_space_id=? and ( videospace0_.deleted = 0)

테스팅을 해보면, 실제로 위와 같이 where 끝 부분에 deleted = false를 체크하는 구문이 붙은 것을 확인할 수 있습니다.




✅ @When의 Trade off


지금까지 JPA를 통해서 손쉽게 Soft Delete를 구현해봤습니다. JPA의 어노테이션을 이용해서 생각보다 쉽고 빠르게 구현이 가능했습니다.

그런데 여기서 생각해볼 점이 있습니다. 위와 같이 Entity 단위로 @Where 어노테이션을 활용하면 모든 Select 쿼리에 Defaultdeleted = false 옵션이 들어갑니다.

이쯤에서, 우리가 Soft Delete를 구현하는 이유에 대해서 다시 한번 생각해봐야합니다.
Soft Delete를 구현하는 큰 이유 중 하나는 삭제된 값을 활용할 수 있게하기 위함입니다.

예를 들어, 어플리케이션 레벨에서 삭제된 데이터를 로직에 활용하거나 클라이언트 단으로 넘겨줘야할 수도 있습니다.
하지만, @Where 어노테이션을 활용한다면 Select 되면서부터 deleted = false인 데이터를 가지고오지 않기 때문에 삭제되지 않은 데이터를 애플리케이션 레벨에서 활용하는 것이 불가능합니다.

@Where 어노테이션을 활용하면 분명 편리성 측면에서 얻는 이점이 크지만, soft delete를 구현 함으로써 사용하고자 하는 기능을 구현하지 못할 수도 있습니다.

실제로 아래 글에서도 @when 어노테이션은 실무에서 사용하기 힘들다고 말하고 있습니다다.

@sql, @where 등을 실무에서 사용하기가 많이 애매합니다.
왜냐하면 실무에서는 경우에 따라서 실제 어떤 데이터가 삭제되었는지 삭제된 데이터도 조회할 수 있어야 하기 때문입니다. 그래서 soft delete 방법을 사용하더라도 좀 불편해도 JPQL에서 삭제 데이터를 제외하고 조회하거나 애플리케이션에서 제외합니다.
출처 : https://www.inflearn.com/questions/304378

정리를 해보자면 삭제된 데이터를 조회하기 위해서는,

  1. 위의 글에서 설명한 방법과 같이 @Where을 사용하지 않고, JPQL에서 삭제데이터를 제외하고 조회하거나, 애플리케이션 레벨에서 제어해주는 방법이 있습니다.
  2. 또한 조금 더 찾아보니, @FilterDef, @Filter 어노테이션을 활용하여 특정 엔티티 매니저 세션에 대해서만 필터를 따로 정의해주는 방법도 있습니다.

이 부분은 비즈니스 명세상으로 프로젝트 성격과 비즈니스 기능 명세에 맞게 선택하는것이 맞는 것 같습니다. 제가 현재 진행 중인 프로젝트에 대해서는 deleted된 데이터를 어플리케이션 레벨에서 활용하는 기능 명세가 없기 때문에 개발에 용이한 @Where를 우선 채택하여 사용했습니다. 추후에 필요한 부분에 있으서는 @Where 어노테이션을 사용하지 않고 애플리케이션 레벨에서 삭제된 데이터를 제외하는 방식을 활용할 예정입니다.




✅ 참고 자료


https://www.baeldung.com/spring-jpa-soft-delete

https://velog.io/@taeha7b/hard-delete-softdelete

https://velog.io/@max9106/JPA-soft-delete

https://www.inflearn.com/questions/304378

profile
어디야 벽벽 / 블로그 이전 -> byuk.dev

0개의 댓글