soft delete 구현

Alex·2024년 6월 21일
0

이슈 트래커

목록 보기
6/21

회원정보같은 건 탈퇴한다고 해서 db에서 바로 지우지 않기도 한다.

나중에 탈퇴한 회원을 복구해달라는 요청이 올 수 있기 때문이다.

소프트 딜리트는 다음과 같이 구현했다.

@SQLDelete(sql = "UPDATE accommodation SET is_deleted = true WHERE id =?")
@FilterDef(
        name = "delete",
        parameters = @ParamDef(name ="isDeleted", type = org.hibernate.type.descriptor.java.BooleanJavaType.class)
)
@Filter(
        name="delete",
        condition = "is_deleted = :isDeleted")
public class Accommodation {

(중략)

private Boolean isDeleted = false;
@Component
@RequiredArgsConstructor
public class FilterManger {

    private final EntityManager entityManager;

    public void enableFilter(String filterName, String paramName, Object paramValue) {
        Session session = entityManager.unwrap(Session.class);
        Filter filter = session.enableFilter(filterName);
        filter.setParameter(paramName, paramValue);
    }

    public void disableFilter(String filterName) {
        Session session = entityManager.unwrap(Session.class);
        session.disableFilter(filterName);
    }

}
public class FilterConstants {

    public static String ACCOMMODATION_FILTER = "delete";
    public static String FILTER_PARAM = "isDeleted";

}
    @Transactional(readOnly = true)
    public List<Accommodation> getAllAccommodation(){

        filterManger.enableFilter(FilterConstants.ACCOMMODATION_FILTER
                , FilterConstants.FILTER_PARAM
                , false);

        List<Accommodation> accommodations = accommodationRepository.findAll();

        filterManger.disableFilter(FilterConstants.ACCOMMODATION_FILTER);
        return accommodations;
    }

소프트 딜리트를 할 때는 @SQLDelete, @Where 이 두가지 어노테이션을 많이 쓴다.

@SQLDelete는 delete 명령을 오버라이드 하는 어노테이션이다.
@Where는 어떤 데이터를 조회할지에 대한 조건을 걸 수 있다.

인텔리제이는 @Where가 곧 deprecated된다는 표시를 해준다.

Note that @Where restrictions are always applied and cannot be disabled. Nor may they be parameterized. They're therefore much less flexible than filters.

필터를 해제하는 게 불가능하고, 파라미터를 넣을수도 없어서 Filter보다 유연하지 않다고 한다.

영한님의 인프런 답변을 보면, 실제로 @Where를 쓰기 애매한 경우가 있다고 한다.

filter를 통해서 is_deleted가 true이거나 false인 상황을 모두 가져올 수 있었다. 파라미터를 적용하지 못한다면 이렇게 소프트 딜리트된 레코드를 가져오지 못할 것이다.

다만, 이 방법에는 문제가 있다.

Hibernate: 
    select
        a1_0.id,
        a1_0.accommodation_type,
        a1_0.address,
        a1_0.amenity,
        a1_0.bed_count,
        a1_0.description,
        a1_0.host_id,
        a1_0.is_deleted,
        a1_0.is_on_sale,
        a1_0.max_capacity,
        a1_0.name,
        a1_0.price,
        a1_0.room_count 
    from
        accommodation a1_0 
    where
        a1_0.id=?
Hibernate: 
    select
        l1_0.accommodation_id,
        l1_0.id,
        l1_0.user_id 
    from
        likes l1_0 
    where
        l1_0.accommodation_id=?
Hibernate: 
    select
        p1_0.accommodation_id,
        p1_0.id,
        p1_0.is_deleted,
        p1_0.url 
    from
        picture p1_0 
    where
        p1_0.accommodation_id=?
Hibernate: 
    select
        sc1_0.accommodation_id,
        sc1_0.id,
        sc1_0.fee,
        sc1_0.interval_days,
        sc1_0.service_type 
    from
        service_charge sc1_0 
    where
        sc1_0.accommodation_id=?
Hibernate: 
    UPDATE
        picture 
    SET
        is_deleted = true 
    WHERE
        id =?
Hibernate: 
    UPDATE
        accommodation 
    SET
        is_deleted = true 
    WHERE
        id =?

연관관계가 있는 경우 위처럼 모두다 select를 해서 update를 해줘야 한다. 즉, 연관관계가 많아질 수록 sql 쿼리가 많이 나가는 거고 그만큼 성능에 영향을 줄 수 밖에 없을 것이다.

뭔가 마땅한 해결법을 찾기 어려웠는데

jpa 소프트딜리트 질문

이런 내용을 발견했다. 지금 요구사항에서는 삭제를 한다고 하면 보통 숙소를 단건으로 삭제한다. 그렇다면, 연관관계에 의한 sql 쿼리가 많아봤자 20개 미만 정도다. 그러면 꼭 이걸 다른 방식으로 해결해야 할까? 이대로 놔두더라도 괜찮을 거 같다는 판단이 든다!

이 부분은 나중에 n+1 문제 해결을 하면서 공부하자.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글