Приведите пример нецелостных данных из-за отсутствия внешнего ключа
Что проверяют
Понимаете ли вы, что ссылочную целостность гарантирует база, а не слой приложения. Для java-разработчика вопрос ещё и про JPA: связь @ManyToOne в сущности сама по себе не создаёт ограничения в схеме, и если ddl писали не вы, ограничения там может не быть вовсе.
Как отвечать
Возьмите пару таблиц и покажите, что ломается. Без внешнего ключа в orders.customer_id проходит вставка заказа на несуществующего клиента, и точно так же удаляется клиент, у которого заказы есть:
insert into orders (id, customer_id, total) values (10, 999, 1500);
delete from customers where id = 42;Дальше начинается интересное. Отчёт через join customers молча теряет такие заказы, выручка занижается, и ошибки никто не видит, потому что запрос отработал успешно. left join вернёт null там, где код ждёт объект. Hibernate при обращении к ленивой ссылке бросит EntityNotFoundException в рантайме, далеко от места, где данные испортили.
Отдельный аргумент: проверка в коде не спасает от гонки. Поток прочитал клиента, параллельная транзакция его удалила, вставка всё равно прошла. Ограничение в базе проверяется в момент записи, поэтому оно и работает.
Полезно добавить, как чинят: ищут сирот через not exists, разбирают их, и только потом навешивают ограничение.
Где спотыкаются
Говорят «у нас целостность на уровне приложения». Её хватает ровно до первого ручного скрипта, второго сервиса в ту же базу и параллельного запроса.
Предлагают on delete cascade как универсальное решение. Каскад не запрещает ошибку, он тихо расширяет удаление: снос одного клиента уносит заказы и платежи, восстанавливать нечего. Чаще нужен именно запрет.
Забывают про индекс на ссылающейся колонке. Удаление родителя заставляет базу искать детей, и без индекса это полное сканирование большой таблицы, из-за чего обычное удаление превращается в блокировку на минуты.