Поскольку это очень распространенный вопрос, я написал эту статью , на которой основан этот ответ.
Переходы состояния объекта
JPA переводит переходы состояния сущности в операторы SQL, такие как INSERT, UPDATE или DELETE.
Когда вы являетесь persist
сущностью, вы планируете выполнение оператора INSERT при EntityManager
сбросе, автоматически или вручную.
когда вы являетесь remove
сущностью, вы планируете инструкцию DELETE, которая будет выполняться, когда сбрасывается контекст постоянства.
Каскадные переходы состояний объекта
Для удобства JPA позволяет распространять переходы состояний сущностей от родительских сущностей к дочерним.
Итак, если у вас есть родительский Post
объект, который @OneToMany
связан с PostComment
дочерним объектом:
comments
Коллекция в Post
сущности, отображается следующим образом :
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
cascade
Атрибут сообщает поставщик JPA передать объект состояние перехода от родительского Post
объекта для всех PostComment
лиц , содержащихся в comments
коллекции.
Итак, если вы удалите Post
сущность:
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
Поставщик JPA собирается PostComment
сначала удалить объект, а когда все дочерние объекты будут удалены, он также удалит Post
объект:
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
Удаление сирот
Когда вы устанавливаете orphanRemoval
атрибут в true
, поставщик JPA собирается планировать remove
операцию, когда дочерняя сущность удаляется из коллекции.
Итак, в нашем случае,
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());
post.getComments().remove(postComment);
Поставщик JPA собирается удалить связанную post_comment
запись, поскольку на PostComment
объект больше не ссылаются в comments
коллекции:
DELETE FROM post_comment WHERE id = 1
НА УДАЛЕННОМ КАСКАДЕ
ON DELETE CASCADE
Определяется на уровне FK:
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
Как только вы это сделаете, если вы удалите post
строку:
DELETE FROM post WHERE id = 1
Все связанные post_comment
сущности автоматически удаляются ядром базы данных. Однако это может быть очень опасной операцией, если вы по ошибке удалите корневую сущность.
Вывод
Преимущество JPA cascade
и orphanRemoval
опций заключается в том, что вы также можете воспользоваться оптимистичной блокировкой для предотвращения потери обновлений .
Если вы используете механизм каскадирования JPA, вам не нужно использовать уровень DDL ON DELETE CASCADE
, что может быть очень опасной операцией, если вы удалите корневую сущность, которая имеет много дочерних сущностей на нескольких уровнях.
Для более подробной информации по этой теме, проверьте эту статью .