데이터베이스에서 데이터를 삭제하는 방법은 두 가지가 존재하는데, 바로 Hard Delete와 SoftDelete 방식이다.
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();
}
}
위와 같이 item의 status필드를 직접 변경해주거나, 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 = ?
@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'
)
이런게 있군요 잘보고 갑니다~
마지막 코드 예시 두 개에서
@SqlDelete 적용 전을 -> @Where 적용 전
@SqlDelete 적용 전을 -> @Where 적용 후로 바꿔야 되는 거 아닌가용