0

Xóa mềm vs Xóa cứng

Đừng "Soft Delete" mọi thứ một cách mù quáng!


Ở trường giáo viên nói qua với tôi mọi dữ liệu khi được sinh ra, để bảo đảm sự toàn vẹn mọi thứ nên được xóa mềm. Nhưng liệu nó luôn như vậy, tôi đã tự tìm hiểu và đúc kết ra một số vấn đề như sau:

1. Phân loại dữ liệu trong hệ thống

Đây là một trong những công đoạn của bước thiết kế dữ liệu thuộc Thiết kế phần mềm nằm trong quy trình phát triển phần mềm

Dữ liệu giao dịch (Transaction/Audit Data)

  • Ví dụ: Chi tiết đơn hàng (Order Items), Hóa đơn, Lịch sử thanh toán.
  • Cơ chế: Nhóm này cực kỳ quan trọng, không bao giờ được xóa cứng hay ẩn đi.
  • Giải pháp: Các trạng thái như CANCELLED, REFUNDED được sinh ra để phục vụ nhóm dữ liệu này.
  • Lý do: Các dòng dữ liệu này phải được bảo vệ nghiêm ngặt để phục vụ báo cáo thuế và kiểm toán tài chính. Hãy nhớ rằng: Luật kế toán luôn tối cao hơn Luật bảo vệ dữ liệu.

Dữ liệu chủ thể (Master Data)

  • Ví dụ: Thông tin tài khoản, Sản phẩm, Bài viết.
  • Cơ chế: Nhóm này áp dụng Soft Delete (Xóa mềm) chuẩn mực. Khi người dùng bấm xóa, hệ thống chỉ thay đổi trạng thái để ẩn dữ liệu khỏi giao diện người dùng.

Dữ liệu tạm thời (Temporary Data)

  • Ví dụ: Session đăng nhập, Mã OTP, Dữ liệu Cache.
  • Cơ chế: Nhóm này được Xóa cứng (Hard Delete) tự động bằng cơ chế TTL (Time-To-Live).

2. Vậy thế nào là "Soft Delete" chuẩn mực?

Thay vì dùng cờ Boolean (is_deleted = true/false), cách làm chuẩn mực là sử dụng một trường thời gian: deleted_at với kiểu dữ liệu DATETIME NULLABLE.

  • Bản ghi còn hoạt động: deleted_at = NULL
  • Bản ghi đã bị xóa: deleted_at = '2026-06-07 09:14:00'

Tại sao deleted_at lại hiệu quả?

Trường này đặc biệt phát huy tác dụng trong trường hợp bảng có các trường định danh duy nhất (UNIQUE field).

Bài toán: Giả sử người dùng chọn xóa tài khoản, nếu ta chỉ xóa mềm bằng cờ is_deleted, chuỗi email của họ vẫn tồn tại trong DB. Khi một người dùng mới muốn đăng ký bằng email đó, xung đột (Conflict) dữ liệu sẽ xảy ra.

Giải pháp: Thiết lập một chỉ mục UNIQUE kết hợp: UNIQUE(email, deleted_at). Khi tài khoản còn hoạt động, deleted_atNULL. Khi bị xóa, deleted_at nhận giá trị thời gian cụ thể. Nhờ vậy, người dùng mới hoàn toàn có thể đăng ký lại bằng email cũ mà không bị trùng lặp index.


3. Quy trình vận hành Soft Delete trong Backend

Để lập trình viên không phải "khổ sở" nhớ thêm điều kiện xóa vào mỗi câu lệnh SQL, chúng ta có hai cách tiếp cận phổ biến:

  • Global Query Filtering: Tại tầng mã nguồn (như Spring Boot, .NET, Laravel), lập trình viên cấu hình một bộ lọc tự động. Mọi câu lệnh lấy dữ liệu sẽ tự động được chèn thêm điều kiện WHERE deleted_at IS NULL.
  • Database View: Tạo ra các bảng ảo (View) chỉ chứa dữ liệu đang hoạt động (Ví dụ: v_active_orders). Các dịch vụ hiển thị giao diện chỉ được phép đọc từ View này để tăng tốc độ quét dữ liệu.

4. Ngoại lệ bắt buộc phải Xóa cứng (Hard Delete)

Dù theo chuẩn "Không xóa dữ liệu", các công ty lớn vẫn phải thiết kế tính năng Xóa cứng vì lý do pháp lý.

Tiêu biểu là Luật bảo vệ dữ liệu (như GDPR tại Châu Âu) có quy định rất nghiêm ngặt về "Quyền được quên" (Right to be forgotten) (Theo Điều 17). Nếu một người dùng yêu cầu xóa tài khoản vĩnh viễn, công ty bắt buộc phải xóa sạch dấu vết thông tin cá nhân của họ khỏi hệ thống trong vòng vài ngày. Nếu cố tình giữ lại dưới dạng "Soft Delete" mà bị phát hiện sẽ phải chịu mức phạt rất nặng.

Lúc này, hành động "Xóa tài khoản" (Delete Account) bắt buộc phía sau hậu đài phải là Hard Delete hoặc Anonymization (Ẩn danh hóa).

Quy trình Hard Delete an toàn (3 Bước)

  • Bước 1 (Xác thực tối cao): Yêu cầu người dùng nhập lại mật khẩu hoặc mã OTP gửi về điện thoại/email để chắc chắn chính chủ đang thực hiện. Đây là hành động không thể đảo ngược nên bắt buộc phải có bước xác nhận này.
  • Bước 2 (Đóng băng tạm thời): Hệ thống lập tức chuyển trạng thái tài khoản sang ẩn (Soft Delete). Người dùng không thể đăng nhập nữa. Hệ thống sẽ giữ dữ liệu này trong vòng 14 đến 30 ngày. Một email thông báo sẽ được gửi đi: "Tài khoản của bạn sẽ bị xóa vĩnh viễn sau 30 ngày. Nếu bạn đổi ý, bấm vào đây để khôi phục".
  • Bước 3 (Xóa vĩnh viễn): Nếu quá thời gian cam kết mà người dùng không khôi phục, một Worker (Tiến trình chạy ngầm) sẽ được kích hoạt tự động để xóa sạch dữ liệu trong DB.

Kỹ thuật Ẩn danh hóa (Anonymization)

Một bài toán đặt ra: Nếu người dùng bị xóa cứng hoàn toàn, thì các dữ liệu Audit/Transaction (như Đơn hàng) liên quan đến họ sẽ ra sao? Như đã phân tích ở phần 1, dữ liệu kế toán/giao dịch là không thể xóa.

Để giải quyết mâu thuẫn này, chúng ta áp dụng Anonymization:

Cơ chế hoạt động:

  • Trước khi xóa tài khoản: Đơn hàng #12345 - Khách hàng: Nguyễn Văn A - SĐT: 0901234... - Số tiền: 500.000đ
  • Sau khi xóa tài khoản (Hard Delete thông tin cá nhân): Đơn hàng #12345 - Khách hàng: [DELETED_USER_9981] - Số tiền: 500.000đ

Bằng cách này, chúng ta vừa tuân thủ nghiêm ngặt luật bảo vệ dữ liệu cá nhân của người dùng, vừa giữ trọn vẹn được tính toàn vẹn của dữ liệu tài chính cho doanh nghiệp.


References


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí