← Назад к вопросам

Что произойдет с записью, ссылающейся по внешнему ключу без указания ON DELETE, при удалении записи из таблицы?

2.7 Senior🔥 31 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Внешние ключи и ON DELETE: поведение по умолчанию

Это фундаментальный вопрос о целостности данных в реляционных базах данных. Ответ зависит от СУБД, но принцип один — защита от orphaned записей.

По умолчанию (без ON DELETE)

Когда вы определяете внешний ключ без явного указания действия при удалении:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    FOREIGN KEY (customer_id) REFERENCES customers(id)
    -- ON DELETE не указан
);

Будет выброшена ошибка (REJECT):

  • При попытке удалить запись из таблицы customers, если на нее есть ссылки из orders
  • СУБД выполнит RESTRICT (или аналогичное действие)
  • Транзакция откатится, запись не будет удалена
  • Пример ошибки: FOREIGN KEY constraint failed

Варианты ON DELETE

Вы можете явно указать поведение при удалении родительской записи:

-- 1. RESTRICT (по умолчанию в большинстве СУБД)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE RESTRICT;
-- Удаление невозможно, если существуют дочерние записи

-- 2. CASCADE (каскадное удаление)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE;
-- При удалении customer удаляются все связанные orders

-- 3. SET NULL (обнуление ссылки)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL;
-- customer_id в orders становится NULL

-- 4. SET DEFAULT (установка значения по умолчанию)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET DEFAULT;
-- customer_id устанавливается на DEFAULT значение

-- 5. NO ACTION (аналог RESTRICT, проверяется в конце транзакции)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE NO ACTION;

Практический пример

-- Таблицы
CREATE TABLE customers (
    id INT PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT NOT NULL,
    amount DECIMAL(10, 2),
    FOREIGN KEY (customer_id) REFERENCES customers(id)
    -- ON DELETE не указан = RESTRICT по умолчанию
);

-- Данные
INSERT INTO customers VALUES (1, "Alice");
INSERT INTO orders VALUES (100, 1, 500.00);

-- Попытка удаления
DELETE FROM customers WHERE id = 1;
-- ❌ ERROR: FOREIGN KEY constraint failed
-- Запись не удалена, транзакция откачена

RESTRICT vs NO ACTION

В PostgreSQL есть различие:

ВариантПоведение
RESTRICTПроверяется сразу (immediate constraint)
NO ACTIONПроверяется в конце транзакции (deferred constraint)
-- RESTRICT (по умолчанию)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE RESTRICT;

-- NO ACTION (проверка отложена)
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED;

Это позволяет обновлять ссылки внутри транзакции без немедленных ограничений.

В контексте Java/ORM (Hibernate, JPA)

@Entity
@Table(name = "orders")
public class Order {
    @Id
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_id", nullable = false)
    // Здесь не указана каскадная настройка
    private Customer customer;
}

// При удалении customer через Hibernate:
// 1. Если orphaned orders существуют — ошибка
// 2. Для CASCADE удаления нужна настройка:
@OneToMany(mappedBy = "customer", cascade = CascadeType.REMOVE)
private Set<Order> orders;

Best Practices

  1. Всегда явно указывайте ON DELETE — не полагайтесь на defaults
  2. Выбирайте стратегию сознательно:
    • RESTRICT — для жестких ограничений (не удалять, пока есть дети)
    • CASCADE — для владение отношения (удалить родителя = удалить детей)
    • SET NULL — для опциональных ссылок (orphan records)
  3. Документируйте причину выбора в комментариях кода
  4. Тестируйте различные сценарии удаления
  5. Синхронизируйте SQL-определение с ORM-конфигурацией (JPA/Hibernate)

Это критически важно для data consistency и предотвращения глухих ошибок в production.

Что произойдет с записью, ссылающейся по внешнему ключу без указания ON DELETE, при удалении записи из таблицы? | PrepBro