В чем разница между каскадным и бесхозным удалением из БД?
В чем разница между
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
а также
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
Этот пример взят из учебника по Java EE, но я до сих пор не понимаю деталей.
3 ответа
Отсюда:-
Каскадное удаление
Пометка ссылочного поля с помощью CascadeType.REMOVE (или CascadeType.ALL, который включает REMOVE) указывает, что операции удаления должны автоматически каскадироваться к объектам сущности, на которые ссылается это поле (на множество объектов сущности может ссылаться поле коллекции):
@Entity class Employee { : @OneToOne(cascade=CascadeType.REMOVE) private Address address; : }
Удаление сироты
JPA 2 поддерживает дополнительный и более агрессивный каскадный режим удаления, который можно указать с помощью элемента orphanRemoval аннотаций @OneToOne и @OneToMany:
@Entity class Employee { : @OneToOne(orphanRemoval=true) private Address address; : }
РАЗНИЦА:-
Разница между двумя настройками заключается в ответе на разрыв отношения. Например, например, когда для поля адреса установлено значение null или для другого объекта Address.
- Если указано orphanRemoval=true, отключенный экземпляр адреса автоматически удаляется. Это полезно для очистки зависимых объектов (например, адреса), которые не должны существовать без ссылки от объекта-владельца (например, сотрудника).
- Если указано только cascade=CascadeType.REMOVE, автоматическое действие не выполняется, поскольку отключение отношения не является удалением
операция.
Простой способ понять разницу между CascadeType.REMOVE
а также orphanRemoval=true
,
Для удаления сирот: если вы вызываете setOrders(null)
, связанные Order
сущности будут удалены в БД автоматически.
Для удаления каскада: если вы вызываете setOrders(null)
, связанные Order
объекты не будут удалены в БД автоматически.
Предположим, у нас есть дочерняя сущность и родительская сущность. Родитель может иметь несколько детей.
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
List<Personnel> myChildernList;
}
orphanRemoval - это концепция ORM, которая сообщает, является ли ребенок сиротой. его также следует удалить из базы данных.
Ребенок становится сиротой, когда к нему нельзя получить доступ от его родителя. Например, если мы удалим obj по индексу i (используя myChildernList.remove(i)) или установим его в null или заменим его новым (staffList.set(i, newChild)), тогда родитель больше не сможет получить доступ к этому дочернему элементу. и ребенок осиротел, поэтому ребенок также обречен на удаление из базы данных (это душераздирающе:()
CascadeType.REMOVE - это концепция уровня базы данных, которая сообщает, что если родитель удален, все связанные с ним записи в дочерней таблице должны быть удалены.
Поскольку этот вопрос очень распространен, этот ответ основан на статье, которую я написал в своем блоге.
CascadeType.REMOVE
В CascadeType.REMOVE
стратегия, которую вы можете настроить явно:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();
или унаследовать его неявно от CascadeType.ALL
стратегия:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();
позволяет размножать remove
операция от родительской сущности к ее дочерним сущностям.
Итак, если мы получим родительский Post
субъект вместе с его comments
коллекция и удалите post
организация:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments
where p.id = :id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
entityManager.remove(post);
Hibernate выполнит три оператора удаления:
DELETE FROM post_comment
WHERE id = 2
DELETE FROM post_comment
WHERE id = 3
DELETE FROM post
WHERE id = 1
В PostComment
дочерние объекты были удалены из-за CascadeType.REMOVE
стратегия, которая действовала так, как если бы мы также удалили дочерние объекты.
Стратегия удаления сирот
Стратегия удаления сирот, которую необходимо настроить через orphanRemoval
атрибут:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
позволяет удалить строку дочерней таблицы при удалении дочернего объекта из коллекции.
Итак, если мы загрузим Post
субъект вместе с его comments
сбор и удаление первого PostComment
от comments
коллекция:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments c
where p.id = :id
order by p.id, c.id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
post.remove(post.getComments().get(0));
Hibernate будет выполнять оператор DELETE для связанного post_comment
строка таблицы:
DELETE FROM post_comment
WHERE id = 2
Для получения дополнительных сведений по этой теме ознакомьтесь также с этой статьей.
Фактически разница заключается в том, пытаетесь ли вы обновить данные (PATCH) или полностью заменить данные (PUT).
Допустим, вы удалили customer
чем использование cascade=REMOVE
также удалит заказы клиентов, которые кажутся преднамеренными и полезными.
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
Допустим, вы обновили customer
с orphanRemoval="true"
он удалит все предыдущие заказы и заменит их предоставленным. (PUT
с точки зрения REST API
)
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
Без orphanRemoval
старые заказы будут сохранены. (PATCH
с точки зрения REST API
)