Ponieważ jest to bardzo częste pytanie, napisałem ten artykuł , na którym opiera się ta odpowiedź.
Przejścia stanu encji
JPA tłumaczy przejścia stanu encji na instrukcje SQL, takie jak INSERT, UPDATE lub DELETE.
Kiedy jesteś persist
bytem, planujesz wykonanie instrukcji INSERT po jej EntityManager
opróżnieniu, automatycznie lub ręcznie.
gdy jesteś remove
bytem, planujesz instrukcję DELETE, która zostanie wykonana po opróżnieniu kontekstu trwałości.
Kaskadowe przejścia stanu encji
Dla wygody JPA pozwala propagować przejścia stanu encji z encji nadrzędnych na encje podrzędne.
Jeśli więc masz Post
jednostkę nadrzędną , która jest @OneToMany
powiązana z PostComment
jednostką podrzędną:
comments
Kolekcja w Post
jednostce są odwzorowywane w sposób następujący:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
Ten cascade
atrybut informuje dostawcę JPA, aby przekazał przejście stanu encji z Post
encji nadrzędnej do wszystkich PostComment
encji zawartych w plikucomments
kolekcji.
Jeśli więc usuniesz Post
jednostkę:
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
Dostawca JPA PostComment
najpierw usunie encję, a kiedy wszystkie encje podrzędne zostaną usunięte, usunie również Post
encję:
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
Usunięcie sieroty
Po ustawieniu orphanRemoval
atrybutu true
dostawca JPA planuje remove
operację, gdy jednostka potomna zostanie usunięta z kolekcji.
W naszym przypadku
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);
Dostawca JPA usunie powiązany post_comment
rekord, ponieważ PostComment
jednostka nie jest już przywoływana w comments
kolekcji:
DELETE FROM post_comment WHERE id = 1
PRZY USUNIĘCIU KASKADA
ON DELETE CASCADE
Jest określona na poziomie FK:
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
Gdy to zrobisz, jeśli usuniesz post
wiersz:
DELETE FROM post WHERE id = 1
Wszystkie powiązane post_comment
jednostki są automatycznie usuwane przez silnik bazy danych. Może to być jednak bardzo niebezpieczna operacja, jeśli przez pomyłkę usuniesz element główny.
Wniosek
Zaletą JPA cascade
i orphanRemoval
opcji jest to, że możesz również skorzystać z optymistycznego blokowania, aby zapobiec utracie aktualizacji .
Jeśli korzystasz z mechanizmu kaskadowego JPA, nie musisz używać poziomu DDL ON DELETE CASCADE
, co może być bardzo niebezpieczną operacją, jeśli usuniesz element główny, który ma wiele elementów potomnych na wielu poziomach.
Więcej informacji na ten temat można znaleźć w tym artykule .