Đăng nhập

Soft Delete là gì? Hướng dẫn “xóa mềm” chuẩn bài: an toàn dữ liệu, dễ khôi phục

Soft delete giúp “xóa mà chưa xóa” để bảo vệ dữ liệu, dễ khôi phục và đáp ứng compliance. Bài viết hướng dẫn cách triển khai với Laravel, Django, Rails, EF Core, kèm best practices, checklist và tài liệu tham khảo.
Soft Delete là gì? Hướng dẫn “xóa mềm” chuẩn bài: an toàn dữ liệu, dễ khôi phục

H2H2Vì sao nên dùng soft delete?

  1. Tránh “bay màu” dữ liệu ngoài ý muốn: Hard delete lỡ tay là đi luôn. Soft delete cho bạn một lớp an toàn.

  2. Compliance và nghiệp vụ: Nhiều ngành yêu cầu lưu vết giao dịch, lịch sử. Soft delete giúp “xóa với người dùng” nhưng vẫn giữ dữ liệu để kiểm toán.

  3. Không làm vỡ quan hệ dữ liệu: Bản ghi bị xóa mềm vẫn tồn tại nên foreign key, báo cáo lịch sử… không bị gãy.

  4. Dễ khôi phục: Un-delete nhanh gọn khi cần.

H2H2Khi nào KHÔNG nên dùng?

  • Dữ liệu thật sự nhạy cảm cần xóa vĩnh viễn ngay (privacy by design).

  • Bảng log quá lớn, giá trị khôi phục thấp, chi phí lưu trữ cao.

  • Trường hợp có yêu cầu pháp lý “phải xóa hoàn toàn” trong thời hạn.


H2H2Các kỹ thuật triển khai phổ biến

H3H31) Cột đánh dấu

  • deleted_at (datetime) – phổ biến nhất. Null = còn sống. Có timestamp = đã xóa.

  • is_deleted (boolean) – true/false. Đơn giản nhưng kém giàu thông tin hơn deleted_at.

Ví dụ SQL:

-- Dùng deleted_at
SELECT *
FROM users
WHERE deleted_at IS NULL;

-- Dùng is_deleted
SELECT *
FROM users
WHERE is_deleted = FALSE;

H3H32) Global query filter / scope

Thiết lập một lớp filter mặc định để mọi truy vấn đều loại bản ghi đã xóa. Có thể thêm method để “bỏ qua” filter khi cần audit hoặc khôi phục.

H3H33) Interceptor/Repository/Service layer

Đóng gói logic xóa mềm tại tầng repository/service để code đồng nhất, dễ test, dễ thay đổi chiến lược sau này.

H3H34) Archiving (lưu trữ)

Sau một thời gian, chuyển dữ liệu đã xóa mềm sang bảng archive để gọn bảng chính và tối ưu chỉ mục.


H2H2Triển khai trong các framework phổ biến

H3H3Laravel

  • Bật soft delete với trait SoftDeletes trong Eloquent Model.

  • Migration thêm cột deleted_at bằng softDeletes().

// migration
Schema::table('posts', function (Blueprint $table) {
    $table->softDeletes(); // tạo cột deleted_at
});

// model
use Illuminate\\Database\\Eloquent\\SoftDeletes;

class Post extends Model
{
    use SoftDeletes; // tự động filter deleted_at IS NULL
}

// xóa mềm
Post::find($id)->delete();

// truy vấn bao gồm cả bản ghi đã xóa
Post::withTrashed()->get();

// chỉ các bản ghi đã xóa
Post::onlyTrashed()->get();

// khôi phục
Post::withTrashed()->find($id)->restore();

// xóa vĩnh viễn (bỏ qua soft delete)
Post::withTrashed()->find($id)->forceDelete();

Tài liệu: Laravel Docs – Eloquent: Soft Deleting.

H3H3Django

  • Sử dụng package như django-safedelete để có manager mặc định lọc record đã xóa, hỗ trợ restore và hard delete.

Repo: django-safedelete trên GitHub.

H3H3Ruby on Rails

  • Dùng gem discard hoặc paranoia để có discarded_at và scope mặc định.

Gems: discard trên RubyGemsparanoia trên GitHub.

H3H3Entity Framework Core (.NET)

  • Tạo cột IsDeleted hoặc DeletedAt, sau đó cấu hình Global Query Filter trong OnModelCreating.

modelBuilder.Entity<Post>().HasQueryFilter(p => p.DeletedAt == null);

Tài liệu: Entity Framework Core Docs.


H2H2Ưu và nhược điểm

H3H3Ưu điểm

  • Khôi phục dữ liệu dễ dàng.

  • Không phá vỡ quan hệ khóa ngoại.

  • Phục vụ audit, báo cáo lịch sử, compliance.

  • Trải nghiệm người dùng “xóa nhưng còn cứu”.

H3H3Nhược điểm

  • Tăng dung lượng bảng.

  • Truy vấn phức tạp hơn nếu quên filter.

  • Hiệu năng giảm nếu chỉ mục chưa tối ưu cho cột xóa mềm.

  • Uniqueness constraint có thể rắc rối khi khôi phục bản ghi cũ.

H3H3Cách khắc phục

  • Lập lịch purge xóa vĩnh viễn sau N ngày hoặc chuyển sang bảng archive.

  • Tạo index cho deleted_at hoặc is_deleted.

  • Dùng Global Scope/Filter để tránh quên điều kiện.

  • Với uniqueness, cân nhắc unique có điều kiện, thêm suffix khi khôi phục, hoặc kiểm tra va chạm trước khi restore.


H2H2Best practices “đỡ đau đầu”

  • Nhất quán: đã chọn soft delete thì áp dụng xuyên suốt domain liên quan.

  • Minh bạch: giải thích rõ với người dùng về cơ chế xóa.

  • Phân quyền: chỉ vai trò phù hợp mới được xem và khôi phục bản ghi đã xóa.

  • Audit log: ghi lại ai xóa, lúc nào, lý do.

  • Observability: metric số lượng bản ghi đã xóa, thời gian khôi phục, kích thước bảng.

  • Test kỹ: xóa, restore, hard delete, cascade, uniqueness…


H2H2Một số pattern thường gặp

  • Soft delete + Versioning: theo dõi lịch sử thay đổi và cả trạng thái xóa.

  • Soft delete + Audit logging: full trace cho compliance.

  • Soft delete + Archiving: giữ bảng chính gọn nhẹ, nhanh hơn.


H2H2FAQ

Soft delete có an toàn không?

An toàn hơn hard delete trong đa số nghiệp vụ vì có thể khôi phục. Nhưng đừng coi là “bất tử” – vẫn cần backup, audit, và quy trình purge.

Có nên dùng cả is_deleteddeleted_at?

Không bắt buộc. deleted_at đã đủ linh hoạt. Chỉ dùng boolean nếu yêu cầu cực đơn giản.

Làm sao để không quên filter?

Thiết lập global scope/filter hoặc repository mặc định lọc. Chỉ “bỏ qua” filter khi có chủ đích.


H2H2Checklist triển khai nhanh

  • [ ] Thêm cột deleted_at và index.

  • [ ] Bật global scope/filter.

  • [ ] Viết service delete, restore, forceDelete.

  • [ ] Lên lịch purge, hoặc chuyển archive.

  • [ ] Thêm audit log.

  • [ ] Viết test cho xóa, restore, uniqueness, cascade.


H2H2Tài liệu tham khảo

Bài trước

Hướng Dẫn Bypass Đăng Nhập Windows 11 Bằng Lệnh

Bài tiếp theo

Thêm cuộn mượt cho web Laravel bằng Lenis (Vite)

Để lại bình luận của bạn

Email của bạn sẽ không được công khai. Các trường bắt buộc được đánh dấu *

Đăng ký nhận bản tin

Đăng ký bản tin email để nhận những bài viết mới nhất trực tiếp trong hộp thư của bạn.
Cảm hứng mỗi ngày, nói không với spam ✨