เนื่องจากนี่เป็นคำถามที่พบบ่อยมากฉันจึงเขียนบทความนี้ขึ้นมาซึ่งคำตอบนี้ขึ้นอยู่กับ
การเปลี่ยนสถานะเอนทิตี
JPA แปลการเปลี่ยนสถานะนิติบุคคลเป็นคำสั่ง SQL เช่น INSERT, UPDATE หรือ DELETE
เมื่อpersist
เอนทิตีของคุณคุณกำลังกำหนดเวลาคำสั่ง INSERT ที่จะดำเนินการเมื่อEntityManager
ถูกฟลัชไม่ว่าจะโดยอัตโนมัติหรือด้วยตนเอง
เมื่อremove
เอนทิตีของคุณคุณกำลังจัดตารางเวลาคำสั่ง DELETE ซึ่งจะถูกดำเนินการเมื่อ Persistence Context ถูกล้างออก
การเปลี่ยนสถานะเอนทิตีแบบเรียงซ้อน
เพื่อความสะดวก 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
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
ซึ่งอาจเป็นการดำเนินการที่อันตรายมากหากคุณลบเอนทิตีรูทที่มีเอนทิตีลูกหลายอันในหลายระดับ
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับหัวข้อนี้ตรวจสอบบทความนี้