DEBI PRAHARADIKA
← Back to Blog Index
Database Engineering2026-07-2825 min read

Membangun Arsitektur Soft-Delete Bertingkat Tanpa Mengacaukan Unique Constraints di MySQL

Pernahkah fitur Soft-Delete merusak validasi email unik di aplikasi Anda? Mari kita bahas solusi arsitekturnya untuk mempertahankan integritas data.

Menghapus data secara permanen (Hard Delete) dari database produksi seringkali menjadi hal yang berisiko untuk aplikasi bisnis berskala besar. Sebagai gantinya, para Engineer menggunakan teknik Soft Delete, biasanya dengan menambahkan kolom is_deleted = 1 atau deleted_at = TIMESTAMP. Teknik ini mengizinkan pengguna untuk me-restore data mereka layaknya fitur Recycle Bin di komputer. Namun, implementasi ini membawa satu masalah besar yaitu munculnya bentrok dengan Unique Constraints. Bayangkan skenario berikut:

  1. Alisa mendaftar dengan email alisa@email.com. (Masuk ke tabel Users).
  2. Alisa menghapus akunnya (Soft Delete, status menjadi deleted_at = NOW()).
  3. Sebulan kemudian, Alisa ingin mendaftar lagi menggunakan email yang sama alisa@email.com.
  4. Database menolak pendaftaran tersebut dengan pesan Error: Duplicate Entry 'alisa@email.com' for key 'users.email_unique'.

Banyak engineer akan mengakalinya dengan membuat indeks gabungan (UNIQUE(email, deleted_at)), namun di MySQL, dua nilai NULL tidak pernah dianggap sama. Artinya, indeks ini justru akan mengizinkan aplikasi Anda memiliki 5 user aktif dengan email yang sama secara bersamaan. Mari kita selesaikan masalah ini dengan dimulai membedah masalah arsitekturnya terlebih dahulu.


1. Membedah Akar Masalah Arsitektur

Arsitektur Soft Delete

Diagram arsitektur di atas menunjukan logika antara kebutuhan aplikasi untuk "menyimpan histori" dengan validasi database yang harus menjamin "keunikan tunggal".

Maka kita membutuhkan mekanisme dimana database mengizinkan banyak record dengan email yang sama asalkan mereka berstatus deleted. Namun disaat yang bersamaan, database harus menolak jika ada lebih dari satu record berstatus active dengan email yang sama. Lalu, bagaimana cara kita mewujudkan skenario ini?. Mari kita cari tahu solusinya di tulisan ini.


2. Mengimplementasikan Formula Unique Hash Logic

Untuk menyelesaikan permasalahan di atas, kita harus "membohongi" mekanisme Unique Constraint di MySQL dengan memberikan nilai modifier yang dinamis.

Formula Soft Delete

Logikanya sangat sederhana yaitu Kunci unik kita tidak hanya (email) tetapi juga (email, MAGIC_VALUE).

  • Jika data dalam keadaan Aktif (deleted_at IS NULL), magic value-nya selalu bernilai 0.
  • Jika data dalam keadaan Terhapus (deleted_at IS NOT NULL), magic value-nya diubah menjadi ID dari baris tersebut (atau bisa dengan Timestamp).

Karena ID adalah Auto Increment atau UUID yang selalu unik, maka setiap record yang dihapus akan memiliki kombinasi uniknya sendiri (contoh: alisa@email.com, 102, lalu alisa@email.com, 104). Namun, jika ada seseorang mencoba mendaftar sebagai alisa@email.com sementara masih ada Alisa yang berstatus aktif (alisa@email.com, 0), database akan mendeteksi duplikasi pada angka 0 tersebut dan menggagalkan eksekusi.

Dengan menggunakan logika ini, selanjutnya mari kita lihat bagaimana cara mengimplementasikannya kedalam sintaks SQL yang praktis tanpa harus membebani source code di sisi aplikasi (backend).


3. Implementasi MySQL

Pada MySQL modern (versi 5.7 dan 8.0+), kita tidak perlu repot melakukan double update. Kita bisa menggunakan fitur Generated Virtual Columns yang secara otomatis menghitung Logic Hash tersebut di level database.

Langkah 1: Merancang Skema Tabel

CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    deleted_at TIMESTAMP NULL DEFAULT NULL,
    
    -- VIRTUAL COLUMN: Ini adalah kunci solusi kita
    delete_hash BIGINT UNSIGNED GENERATED ALWAYS AS (
        IF(deleted_at IS NULL, 0, id)
    ) VIRTUAL,
    
    -- Mendaftarkan Unique Constraint
    UNIQUE KEY users_email_unique (email, delete_hash)
) ENGINE=InnoDB;

Langkah 2: Lifecycle Transaksi (Test Case)

  1. Registrasi Awal (Sukses)
INSERT INTO users (name, email) VALUES ('Alisa', 'alisa@email.com');
-- Hasil internal: delete_hash = 0. Tabel aman.
  1. Alisa Menghapus Akun (Soft Delete)
UPDATE users SET deleted_at = NOW() WHERE email = 'alisa@email.com';
-- Hasil internal: delete_hash otomatis berubah menjadi '1' (mengikuti ID).
  1. Alisa Mendaftar Ulang dengan Email Lama (Sukses!)
INSERT INTO users (name, email) VALUES ('Alisa Baru', 'alisa@email.com');
-- Hasil internal: delete_hash = 0. Sukses karena '0' belum terpakai oleh alisa@email.com manapun.
  1. Bob Mencoba Memakai Email Alisa yang Aktif (Gagal/Error!)
INSERT INTO users (name, email) VALUES ('Bob Penipu', 'alisa@email.com');
-- ERROR 1062 (23000): Duplicate entry 'alisa@email.com-0' for key 'users_email_unique'
-- Integritas data berhasil dipertahankan!

Dengan database yang saat ini sudah tahan terhadap anomali data, selanjutnya mari kita lihat bagaimana cara merancang antarmuka (UI) yang memanfaatkan kemampuan ini agar tim operasional bisa bekerja dengan aman.


4. Dashboard Admin (Recycle Bin/Trash)

Secara operasional, pemisahan tingkat data ini akan mempermudah tim Customer Support atau Administrator untuk mengelola siklus pengguna tanpa khawatir kehilangan data akibat kelalaian operasional (human error).

Dashboard UI Soft Delete

Desain antarmuka Admin Dashboard di atas memisahkan tampilan pengguna aktif dengan Archived Users (Pengguna Terhapus). Dengan arsitektur yang sudah kita bangun, tombol [RESTORE] akan secara otomatis mengembalikan deleted_at menjadi NULL.

Apabila pengguna mencoba me-restore akun lama, sementara sudah ada akun baru yang memakai email yang sama secara aktif, Database akan mengembalikan perlindungan Error Duplicate, mencegah timbulnya kerusakan data massal di level aplikasi. Hal ini membuat aplikasi Anda akan sangat aman dan handal.


Soft-Delete tidak boleh diimplementasikan secara setengah matang. Menggabungkan kolom Timestamp dengan Generated Virtual Columns pada MySQL adalah sebuah karya teknis yang menyelesaikan perseteruan antara business requirements (historical data retention) dengan Data integrity.

Dengan memahami low-level design pattern ini, aplikasi yang Anda rancang akan sanggup bertahan menghadapi kompleksitas operasional tanpa cacat logika.

Tetap semangat belajar, bereksplorasi, dan jangan pernah berhenti membangun hal-hal yang luar biasa!