Ответ
Soft Delete (мягкое удаление) — это паттерн, при котором запись в базе данных не удаляется физически оператором DELETE, а помечается как удалённая с помощью специального флага (например, колонки deleted_at типа TIMESTAMP или is_deleted типа BOOLEAN). Это позволяет сохранять данные для истории, аудита или возможности восстановления.
Типичная реализация:
- В таблицу добавляется поле
deleted_at(NULL по умолчанию). - При "удалении" в это поле записывается текущая дата и время (вместо настоящего удаления).
- Все основные выборки (
SELECT) автоматически фильтруют записи по условиюWHERE deleted_at IS NULL.
Пример на SQL:
-- Создание таблицы
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
deleted_at TIMESTAMP NULL DEFAULT NULL
);
-- "Мягкое" удаление пользователя с id = 5
UPDATE users SET deleted_at = NOW() WHERE id = 5;
-- Выборка только активных пользователей
SELECT * FROM users WHERE deleted_at IS NULL;
-- Выборка всех пользователей, включая удалённых
SELECT * FROM users;
-- Восстановление пользователя
UPDATE users SET deleted_at = NULL WHERE id = 5;
Реализация в Laravel Eloquent:
Laravel предоставляет трейт SoftDeletes для удобной работы с этим паттерном.
// В модели
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;
class User extends Model {
use SoftDeletes; // Добавляет функциональность мягкого удаления
protected $dates = ['deleted_at'];
}
// Использование
$user = User::find(1);
$user->delete(); // Заполняет колонку `deleted_at` текущей датой
// Стандартные запросы игнорируют удалённые записи
$activeUsers = User::all(); // Только где deleted_at IS NULL
// Для работы со всеми записями
$allUsers = User::withTrashed()->get();
$trashedUsers = User::onlyTrashed()->get();
// Восстановление
User::withTrashed()->find(1)->restore(); // Обнуляет deleted_at
// Полное физическое удаление
User::withTrashed()->find(1)->forceDelete();
Преимущества Soft Delete:
- Безопасность данных: Возможность восстановить случайно удалённые данные.
- Целостность ссылок: Внешние ключи не нарушаются, так как запись физически остаётся в таблице.
- Аудит: Сохраняется полная история всех записей.
Недостатки и сложности:
- Усложнение запросов: Необходимо всегда помнить о фильтрации по
deleted_at. В Laravel это решается на уровне ORM. - Рост базы данных: Требуется периодическая архивация или очистка старых "удалённых" записей.
- Уникальные индексы: Могут возникнуть конфликты, если уникальность должна учитывать только активные записи. Решение — использовать составные индексы, включающие
deleted_at.
Ответ 18+ 🔞
Слушай, объясняю про эту вашу «мягкую удалёнку», как будто я тебе на кухне за пивом рассказываю. Представь: ты не выбрасываешь старый диван на помойку, а просто задвигаешь его на балкон и вешаешь табличку «не трогать, тут мыши завелись». Вот это и есть Soft Delete, ёпта.
Суть в чём:
В базе данных запись не выпиливают нахуй через DELETE, а просто ставят ей флажок — типа, «удалена, но мы её помним». Обычно это поле deleted_at (когда удалили) или is_deleted (да или нет). И все нормальные запросы потом этот флажок смотрят и удалённое игнорят. Хитрая жопа, но иногда нужная.
Как это выглядит в коде:
-- Допустим, есть таблица с юзерами
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
deleted_at TIMESTAMP NULL DEFAULT NULL -- Вот наш волшебный флажок!
);
-- Хотим удалить юзера с id=5. Но по-мягкому!
UPDATE users SET deleted_at = NOW() WHERE id = 5; -- Просто ставим дату, и всё
-- Когда выбираем активных юзеров, всегда добавляем условие
SELECT * FROM users WHERE deleted_at IS NULL; -- Только те, у кого NULL, т.е. живые
-- А если надо всех, включая «балконных» — просто выбираем без условия
SELECT * FROM users;
-- Передумали? Восстанавливаем!
UPDATE users SET deleted_at = NULL WHERE id = 5; -- И он снова в строю
А в Laravel это вообще ебушки-воробушки, там встроенная фича есть.
// В модели просто добавляем трейт
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;
class User extends Model {
use SoftDeletes; // Всё, магия началась
protected $dates = ['deleted_at'];
}
// Использование — проще некуда
$user = User::find(1);
$user->delete(); // Физически не удалит, просто в deleted_at время запишет
// Все обычные запросы будут автоматом игнорить удалённых
$activeUsers = User::all(); // Только живые, где deleted_at IS NULL
// Хочешь посмотреть, что на балконе валяется?
$allUsersWithTrash = User::withTrashed()->get(); // Все до единого
$onlyTrashed = User::onlyTrashed()->get(); // Только те, кого «удалили»
// Ой, передумал, верни диван обратно в комнату!
User::withTrashed()->find(1)->restore(); // deleted_at станет NULL
// А если реально надо нахуй выкинуть — тогда forceDelete
User::withTrashed()->find(1)->forceDelete(); // Вот теперь всё, приехали
Зачем этот цирк? Плюсы:
- Не страшно ошибиться. Случайно удалил — восстановил, и волнение ебать прошло. Не надо бегать с бэкапами.
- История сохраняется. Всегда можно посмотреть, что и когда «удалили». Для аудита — то, что надо.
- Целостность не ебётся. Внешние ключи не ругаются, потому что запись-то на месте.
Но и минусов овердохуища:
- Запросы усложняются. Надо везде помнить про этот
deleted_at IS NULL, а то вдруг удалённого юзера в отчёт включишь. В Laravel, конечно, Eloquent за тебя думает, но в сыром SQL — головняк. - База распухает. Удалённые записи копятся, как хлам на балконе. Рано или поздно придётся проводить «генеральную уборку» и чистить старьё.
- С уникальностью могут быть косяки. Допустим, у тебя email должен быть уникальным. Если юзер «удалился», а потом новый пытается зарегиться с таким же email — может быть конфликт, потому что запись-то в базе есть. Тут уже надо мозги включать, например, составные индексы делать.
Короче, инструмент полезный, но не серебряная пуля. Используй, когда нужна возможность отката или история изменений. А если данные реально мусорные и восстанавливать их не планируется — лучше сразу DELETE и не мучать базу.