Как JPA/Hibernate управляет удалением дочерних сущностей при удалении родительской?

«Как JPA/Hibernate управляет удалением дочерних сущностей при удалении родительской?» — вопрос из категории Базы данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В JPA/Hibernate автоматическое удаление дочерних сущностей (подобъектов) зависит от настроек каскадирования (cascade) и типа связи. По умолчанию каскадное удаление отключено.

1. Каскадное удаление (CascadeType.REMOVE или CascadeType.ALL) При удалении родителя все связанные дочерние сущности также удаляются из БД.

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;

    // Все дочерние Child будут удалены при удалении этого Parent
    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private List<Child> children;
}

2. Без каскадного удаления (дефолтное поведение) Дочерние сущности остаются в базе данных. Их внешний ключ (parent_id) станет NULL (если столбец допускает NULL), что может привести к нарушению целостности, если столбец NOT NULL.

@OneToMany(mappedBy = "parent") // Каскад не указан
private List<Child> children;

3. Удаление «сирот» (orphanRemoval = true) Более строгий механизм, чем CascadeType.REMOVE. Дочерняя сущность удаляется не только при удалении родителя, но и при ее удалении из коллекции (отсоединении).

@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children;
// Если child удалить из коллекции children, он будет удален из БД

Важные нюансы:

  • Для связей @ManyToMany каскадное удаление нужно настраивать явно, либо управлять связующей таблицей вручную.
  • Каскадные операции выполняются в порядке, определенном JPA провайдером (Hibernate), обычно после всех изменений в persistence-контексте.