데이터베이스에서 데이터를 삭제할 때 정책에 따라 Hard Delete와 Soft Delete로 나눌 수 있다. Hard Delete는 물리 삭제, Soft Delete는 논리 삭제로도 부른다. 물리 삭제는 데이터베이스 상에서 완전히 제거하는 것이고, 논리 삭제는 데이터를 남겨두되 컬럼을 별도로 만들어서 삭제 여부를 확인하는 것이다. 보통 삭제일시 컬럼의 null 여부 또는 삭제여부 컬럼의 true와 false 값을 확인한다.
논리 삭제의 경우에는 데이터를 삭제하지 않으므로 결과적으로는 특정 컬럼을 update 한다. 이때 @SQLDelete 라는 어노테이션을 유용하게 사용할 수 있다. 이 어노테이션은 데이터를 삭제하는 로직을 작성하면, 데이터를 삭제하는 대신에 미리 설정한 특정 컬럼의 값을 변경해준다. 다음과 같이 사용할 수 있다.
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.time.LocalDateTime;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
@Entity
// UPDATE 테이블명 SET 삭제여부판별컬럼명=조건 WHERE 변경할 데이터
@SQLDelete(sql = "UPDATE member SET withdrawal_status= true WHERE member_id = ?")
// clause = 삭제여부판별컬럼명=조건
@Where(clause = "withdrawal_status = true")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private Long id;
private boolean withdrawalStatus;
}
위 예시는 회원이 탈퇴할 때, 탈퇴 상태를 true로 갱신한다. 만약 삭제일시로 판별하고 싶다면 다음과 같이 작성할 수도 있다.
@SQLDelete(sql = "UPDATE member SET withdrawal_date = CURRENT_TIMESTAMP WHERE member_id = ?")
CURRENT_TIMESTAMP는 현재 시각을 의미한다. 이 설정은 데이터 삭제시에 탈퇴일시 컬럼을 현재 시각으로 갱신한다. 이때 탈퇴여부는 null 여부로 판별할 수 있다.
이 과정을 거치면 데이터는 논리적으로 삭제되었다. 그러나 데이터 조회 시에는 논리삭제 여부와 관계없이 모두 조회되므로 @Where 어노테이션을 이용하여 논리적으로 삭제된 데이터는 조회되지 않도록 조치를 해야한다. 다만 버전에 따라 다르게 조건을 설정할 수 있다. 위의 예시(@Where)는 deprecated 되었고 현재 Hibernate 6.3에서는 @SQLRestriction 사용을 권장한다. 변경된 형식은 다음과 같다.
@SQLRestriction("status <> 'DELETED'")
//이 어노테이션 관련 여러 테스트를 진행해봤는데, 클래스에 이 어노테이션이 붙어있으면 삭제여부 컬럼의 update문이 나가지 않고, select문만 나가는 버그가 발생하는데 혹시 이유 아시는 분 있다면 댓글 부탁드립니다,,,
//컬럼에 붙이면 update문 정상동작 하는 것으로 보입니다! 근데 soft delete한 내역까지 다 보여요 ^^... 아마 @SQLRestriction 문제같은데 이유를 잘 모르겠어요,,, 저도 버그 고치면 글 수정하도록 하겠습니다
'DB > JDBC & JPA' 카테고리의 다른 글
[JPA] @CreatedDate와 @LastModifiedDate (1) | 2024.01.29 |
---|