
데이터를 삭제할 때, 실제로 삭제할 것인가 아니면 삭제된 것처럼 처리만 할 것인가?
Soft Delete와 Hard Delete는 바로 이 질문에 대한 두 가지 접근 방식입니다.
| 구분 | Soft Delete | Hard Delete |
|---|---|---|
| 의미 | 데이터를 삭제하지 않고 ‘삭제된 것처럼 표시’ | 데이터를 실제로 삭제 |
| 방식 | deleted_yn = 'Y' 또는 deleted_at = now() 등 필드 값 변경 | DELETE FROM table WHERE id = ? 등으로 데이터 자체 제거 |
| 주로 사용되는 필드 | delete_yn, deleted, deleted_at 등 | 없음 |
| 항목 | Soft Delete | Hard Delete |
|---|---|---|
| 데이터 존재 여부 | DB에 존재 (삭제 표시) | DB에서 완전히 제거 |
| 복구 가능성 | O (필드만 변경하면 복구 가능) | X (복구 어려움) |
| 감사 로그 | 유지 가능 (삭제 시점 확인 가능) | 별도 로그 기록 필요 |
| 쿼리 복잡도 | WHERE deleted_yn = 'N' 필요 | 단순 쿼리 |
| 성능 및 공간 | 오래된 데이터 누적 가능성 | 테이블 정리되어 성능 유리 |
| 사용 예시 | 회원 탈퇴, 게시판, 주문 이력 등 | 로그, 캐시, 일시적 데이터 등 |
CREATE TABLE coffee_order (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_name VARCHAR(100),
coffee_name VARCHAR(100),
order_time DATETIME,
deleted_yn CHAR(1) DEFAULT 'N',
deleted_at DATETIME DEFAULT NULL
);
CREATE PROCEDURE sp_jooniljjang_coffee_order_soft_delete (
IN p_order_id INT
)
BEGIN
UPDATE coffee_order
SET deleted_yn = 'Y',
deleted_at = NOW()
WHERE order_id = p_order_id;
END;
CREATE PROCEDURE sp_jooniljjang_coffee_order_hard_delete (
IN p_order_id INT
)
BEGIN
DELETE FROM coffee_order
WHERE order_id = p_order_id;
END;
@Entity
@SQLDelete(sql = "UPDATE user SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
public class User {
@Id
private Long id;
private String name;
private Boolean deleted = false;
}
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByDeletedFalse();
}
@Transactional
public void softDeleteUser(Long userId) {
userRepository.deleteById(userId); // 실제로는 SQLDelete 어노테이션이 동작
}
| 상황 | 추천 방식 |
|---|---|
| 사용자 정보, 게시글, 주문 내역 등 이력 보존 필요 | ✅ Soft Delete |
| 복구 가능성을 고려하거나 삭제 로그를 남기고 싶을 때 | ✅ Soft Delete |
| 로그, 캐시, 임시 데이터 등 영구 보존이 불필요할 때 | ✅ Hard Delete |
| 저장 공간과 성능이 중요한 경우 | ✅ Hard Delete |
📌 실무에서는 Soft Delete 방식을 선택한 경우, 모든 SELECT 쿼리에
deleted_yn = 'N'조건을 빠뜨리지 않도록 주의하세요.
JPA에서는@Where(clause = "deleted = false")와@SQLDelete를 활용해 반복 방지 가능합니다.