SoftDelete시, 데이터 조회&삭제 동작 지정하기

hongo·2023년 7월 22일
1

SoftDelete란?

데이터베이스에서 데이터를 삭제하는 방법은 두 가지가 존재하는데, 바로 Hard DeleteSoftDelete 방식이다.

  • Hard Delete는 delete 쿼리를 사용해 데이터베이스에서 데이터를 실제로 삭제하는 방법이다.
  • SoftDelete는 데이터에 deleted같은 컬럼을 추가해, 해당 컬럼으로 데이터의 삭제 여부를 나타내는 것이다. 실제 데이터베이스에서 데이터가 삭제되지는 않고, deleted컬럼의 값만 변화한다.

나는 이번 프로젝트에서 Soft Delete방식을 사용했다.

public enum StatusType {

    USABLE,
    DELETED
}
@Getter
@MappedSuperclass
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

    ...
        
    @Column(nullable = false)
    @Enumerated(value = STRING)
    private StatusType status = USABLE;

    protected BaseEntity(final StatusType status) {
        this.status = status;
    }

    public boolean isDeleted() {
        return this.status.equals(DELETED);
    }

    public void changeStatusToDeleted() {
        this.status = DELETED;
    }
}

BaseEntity에 데이터의 삭제 여부를 표현하기 위한 status필드를 만들고, BaseEntity를 상속한 Item도메인을 생성했다.

@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
public class Item extends BaseEntity {
	...

}

엔티티 삭제시 자동으로 status를 Deleted로 업데이트하기(@SqlDelete)

@SqlDelete를 사용해 엔티티가 삭제될 때 어떤 동작을 할 것인지를 지정해줄 수 있다.

SoftDelete를 한다면, 객체를 삭제할 때 delete쿼리대신 update쿼리를 사용해 status값을 Deleted로 변경시켜주어야 한다.

@Service
@Transactional
public class ItemService {
    ...
        
    public void delete(final Long itemId) {
            ...
            item.changeStatusToDeleted();
        }
}

위와 같이 itemstatus필드를 직접 변경해주거나, itemRepository를 통해 객체를 새로 update해서 SoftDelete를 수행할 수 있다.

하지만 @SqlDelete를 사용하면, repository에서 entity를 delete할 때 어떤 쿼리를 수행할 것인지를 지정할 수 있다.

@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
@SQLDelete(sql = "UPDATE item SET status = 'DELETED' WHERE id = ?")
public class Item extends BaseEntity {
}
# @SqlDelete 적용 전 itemRepository.delete() 호출
Hibernate: 
    delete 
    from
        item
    where
        id=?
# @SqlDelete 적용 후 itemRepository.delete() 호출
Hibernate: 
    UPDATE
        item 
    SET
        status = 'DELETED' 
    WHERE
        id = ?

연관 객체를 불러올 때 Deleted된 객체만 가져오기(@Where)

@Where를 사용해 객체를 select해올 때 어떤 객체들만 가져올 것인지를 지정할 수 있다.

@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
@SQLDelete(sql = "UPDATE item SET status = 'DELETED' WHERE id = ?")
@Where(clause = "status = 'USABLE'")
public class Item extends BaseEntity {
}
# @Where 적용 전 itemRepository.findAll() 호출
Hibernate: 
    select
        i1_0.id,
        i1_0.created_at,
        i1_0.modified_at,
        i1_0.status,
        i1_0.title 
    from
        item i1_0 
    where
        i1_0.id=?
# @Where 적용 전 itemRepository.findAll() 호출
Hibernate: 
    select
        i1_0.id,
        i1_0.created_at,
        i1_0.modified_at,
        i1_0.status,
        i1_0.title 
    from
        item i1_0 
    where
        i1_0.id=? 
        and (
            i1_0.status = 'USABLE'
        )

2개의 댓글

comment-user-thumbnail
2023년 7월 22일

이런게 있군요 잘보고 갑니다~

마지막 코드 예시 두 개에서
@SqlDelete 적용 전을 -> @Where 적용 전
@SqlDelete 적용 전을 -> @Where 적용 후로 바꿔야 되는 거 아닌가용

1개의 답글