Что такое constraint в базе данных
Что проверяют
Понимаете ли вы, что целостность данных задаётся в схеме, а не только в коде сервиса. Для java-разработчика вопрос практический: половина багов с кривыми строками в таблице появляется там, где проверку оставили в валидаторе приложения, а два соседних сервиса пишут в ту же таблицу напрямую.
Как отвечать
Constraint это декларативное правило, которое СУБД проверяет сама при каждой вставке и обновлении. Нарушил, получил ошибку и откат транзакции.
Перечислите типы и скажите, зачем каждый:
NOT NULL: значение обязано присутствовать. UNIQUE: дублей нет, при этом несколько NULL в большинстве СУБД допускаются. PRIMARY KEY: уникальность плюс NOT NULL, идентификатор строки. FOREIGN KEY: ссылка существует в родительской таблице, поведение при удалении задаётся через ON DELETE RESTRICT, CASCADE или SET NULL. CHECK: произвольное булево условие по столбцам строки.
create table orders (
id bigserial primary key,
user_id bigint not null references users(id) on delete restrict,
status text not null check (status in ('new','paid','cancelled')),
amount numeric(12,2) not null check (amount > 0),
constraint orders_external_key_uniq unique (user_id, external_key)
);Сильный ответ добавит: ограничение стоит именовать явно, тогда в логе видно, какое правило сработало, а Hibernate отдаёт нарушение как ConstraintViolationException, и по имени приложение решает, какую понятную ошибку показать пользователю.
Где спотыкаются
Говорят, что проверка в коде надёжнее. Она не выдерживает гонок: два параллельных запроса одинаково убедятся, что записи нет, и оба её вставят. От дубля спасает только уникальное ограничение.
Путают constraint и индекс. Уникальность в PostgreSQL действительно опирается на индекс, но FOREIGN KEY и CHECK индекса не создают, а внешний ключ без индекса на дочерней стороне делает удаление родителя очень медленным.
Не знают, что делать с ограничением на заполненной таблице. Добавить NOT NULL или CHECK можно лишь после того, как данные приведены в порядок, иначе миграция упадёт; в PostgreSQL помогает вариант NOT VALID с отдельной валидацией потом.