Ограничения целостности
Constraint заставляет базу проверять инвариант независимо от того, какой экземпляр приложения или скрипт изменяет данные.
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
state VARCHAR(20) NOT NULL,
total NUMERIC(12, 2) NOT NULL,
created_at TIMESTAMP NOT NULL,
CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id),
CONSTRAINT ck_orders_total
CHECK (total >= 0),
CONSTRAINT ck_orders_state
CHECK (state IN ('NEW', 'PAID', 'CANCELLED'))
);Основные ограничения
NOT NULL
Значение обязательно. Пустая строка остается строкой и не нарушает NOT NULL.
UNIQUE
Запрещает повтор комбинации столбцов. Поведение нескольких NULL в unique constraint зависит от стандарта, СУБД и дополнительных опций — важную семантику задают явно.
UNIQUE (order_id, sku)PRIMARY KEY
Главный ключ строки: уникален и не допускает NULL. Один constraint может быть составным.
FOREIGN KEY
Проверяет существование родительского ключа. Политика удаления должна соответствовать домену:
RESTRICT/NO ACTION— запретить удаление при ссылках;CASCADE— удалить зависимые строки;SET NULL— убрать ссылку, если столбец допускаетNULL.
Cascade удобен, но способен удалить большой граф данных; это часть модели, а не техническая мелочь.
CHECK
Проверяет условие для строки. В SQL CHECK обычно отклоняет FALSE, но пропускает UNKNOWN, поэтому обязательный столбец требует отдельного NOT NULL.
quantity INTEGER NOT NULL CHECK (quantity > 0)Когда constraint сложен
Правило между множеством строк — например «не больше одной активной записи» — иногда выражается частичным unique index. Правило между сервисами обычный constraint одной БД не охватит.
Изменение существующей таблицы
Перед добавлением constraint нужны:
- поиск нарушающих строк;
- очистка/backfill;
- оценка блокировки и времени проверки;
- безопасное развертывание приложения;
- мониторинг нарушения после включения.
Связано: Ключи БД, Транзакции принцип ACID, Нормализация денормализация.
Вопросы
Чем NOT NULL отличается от CHECK? NOT NULL явно запрещает отсутствие значения; обычный CHECK может пропустить UNKNOWN.
Зачем constraint, если проверяет Java-код? Базу меняют несколько процессов, версии приложения и скрипты; constraint остается общей последней защитой.
Создает ли foreign key индекс на дочернем столбце? Не обязательно.
Когда опасен CASCADE? Когда удаление родителя запускает неожиданно большой или критичный каскад.
Можно ли constraint защитить правило между двумя независимыми БД? Нет, нужен распределенный протокол и модель согласованности.