데이터베이스에서 데이터를 삭제하는 방법은 두 가지가 존재하는데, 바로 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 적용 후로 바꿔야 되는 거 아닌가용