JPA 2.0 orphanRemoval
속성 에 대해 약간 혼란 스럽습니다 .
JPA 공급자의 DB 생성 도구를 사용 ON DELETE CASCADE
하여 특정 관계에 대한 기본 데이터베이스 DDL을 만들 때 필요하다는 것을 알 수 있다고 생각 합니다.
그러나 DB가 존재하고 이미 ON DELETE CASCADE
관계 가있는 경우 삭제를 적절하게 단계 화하기에 충분하지 않습니까? 무엇을 않는 orphanRemoval
추가합니까?
건배
JPA 2.0 orphanRemoval
속성 에 대해 약간 혼란 스럽습니다 .
JPA 공급자의 DB 생성 도구를 사용 ON DELETE CASCADE
하여 특정 관계에 대한 기본 데이터베이스 DDL을 만들 때 필요하다는 것을 알 수 있다고 생각 합니다.
그러나 DB가 존재하고 이미 ON DELETE CASCADE
관계 가있는 경우 삭제를 적절하게 단계 화하기에 충분하지 않습니까? 무엇을 않는 orphanRemoval
추가합니까?
건배
답변:
orphanRemoval
와는 아무런 관련이 없습니다 ON DELETE CASCADE
.
orphanRemoval
전적으로 ORM에 특정한 것 입니다. 더 이상 "부모"엔터티에서 참조되지 않을 때 (예 : 부모 엔터티의 해당 컬렉션에서 하위 엔터티를 제거 할 때) "하위"엔터티가 제거되도록 표시합니다.
ON DELETE CASCADE
A는 데이터베이스 고유의 건 은 "부모"행이 삭제 될 때, 그것은 데이터베이스에 "아이"행을 삭제합니다.
때 Employee
엔티티 객체가 제거되고, 제거 작업은 참조에 종속되는 Address
엔티티 객체. 이와 관련하여, orphanRemoval=true
과 cascade=CascadeType.REMOVE
동일하며, 만약 orphanRemoval=true
지정된, CascadeType.REMOVE
중복.
두 설정의 차이점은 관계를 끊는 것에 대한 응답입니다. 예를 들어, 주소 필드 null
를 다른 Address
개체 로 설정 하거나 다른 개체 로 설정하는 경우
경우 orphanRemoval=true
IS 지정한 분리 Address
인스턴스가 자동으로 제거됩니다. 이는 Address
소유자 객체 (예 :)의 참조없이 존재하지 않아야 하는 종속 객체 (예 :)를 정리하는 데 유용합니다 Employee
.
cascade=CascadeType.REMOVE
지정된 경우에만 관계를 끊는 것이 제거 작업이 아니므로 자동 작업이 수행되지 않습니다.
고아 제거로 인한 댕글 링 참조를 피하려면이 기능은 개인 비공유 종속 개체를 보유하는 필드에 대해서만 활성화해야합니다.
이것이 더 명확 해지기를 바랍니다.
컬렉션에서 하위 엔터티를 제거하는 순간 해당 하위 엔터티도 DB에서 제거됩니다. orphanRemoval은 또한 부모를 변경할 수 없음을 의미합니다. 직원이있는 부서가있는 경우 해당 직원을 제거하여 다른 부서에 배치 한 경우, 해당 직원을 플러시 / 커밋 할 때 데이터베이스에서 실수로 제거했습니다 (둘 중 먼저 발생). 그 부모의 자녀가 다른 부모에게 존재하지 않는 것이 확실한 한 사기는 orphanRemoval을 true로 설정하는 것입니다. orphanRemoval을 켜면 캐스케이드 목록에 자동으로 제거가 추가됩니다.
department.remove(emp);
를 commit()
DDL에 대한 동등한 JPA 맵핑 ON DELETE CASCADE
은 cascade=CascadeType.REMOVE
입니다. 고아 제거는 "부모"개체와의 관계가 파괴 될 때 종속 개체가 제거됨을 의미합니다. 예를 들어 @OneToMany
항목 관리자 에서 자식 을 명시 적으로 제거하지 않고 관계 에서 자식을 제거하는 경우를 예로들 수 있습니다.
cascade=CascadeType.REMOVE
와 동일하지 않습니다 ON DELETE CASCADE
. 응용 프로그램 코드에서 제거하고 DDL, DB에서 실행되는 다른 DDL에는 영향을 미치지 않습니다. stackoverflow.com/a/19696859/548473
차이점은 다음과 같습니다.
-orphanRemoval = true : "자식"엔터티가 더 이상 참조되지 않으면 제거됩니다 (부모가 제거되지 않을 수 있음).
-CascadeType.REMOVE : "자식"개체는 "부모"가 제거 된 경우에만 제거됩니다.
이것은 매우 일반적인 질문 이므로이 답변을 기반으로하는이 기사를 작성 했습니다.
JPA는 엔티티 상태 전이를 INSERT, UPDATE 또는 DELETE와 같은 SQL 문으로 변환합니다.
당신은 때 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<>();
이 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
. 이는 여러 레벨에 많은 하위 엔티티가있는 루트 엔티티를 제거하는 경우 매우 위험한 작업 일 수 있습니다.
CascadeType
. 보완적인 메커니즘입니다. 지금, 당신은 지속으로 제거를 착각하고 있습니다. 고아 제거는 참조되지 않은 연결을 삭제하는 반면 지속은 새 엔티티를 저장하는 것입니다. 이러한 개념을 더 잘 이해하려면 답변에 제공된 링크를 따라야합니다.
@GaryK의 대답은, 내가 설명을 찾는 시간을 절대적으로 큰 썼다되는 orphanRemoval = true
대 CascadeType.REMOVE
그리고 그것은 나를 이해할 수있었습니다.
요약 : 객체 ( )를 삭제 하고 자식 객체도 제거하려는 경우 에만orphanRemoval = true
동일하게 작동합니다 .CascadeType.REMOVE
entityManager.delete(object)
완전히 다른 상황에서 우리가 같은 데이터를 가져 와서 List<Child> childs = object.getChilds()
자식 ( entityManager.remove(childs.get(0)
) 을 제거 orphanRemoval=true
하면 해당 엔티티 childs.get(0)
가 데이터베이스에서 삭제됩니다.
고아 제거는 다음과 같은 시나리오에서 ON DELETE CASCADE와 동일한 효과를 갖습니다. Student 테이블이 id_guide를 FK로 갖도록 Student와 Guide 테이블 간의 외래 키 관계.
@Entity
@Table(name = "student", catalog = "helloworld")
public class Student implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name = "id_guide")
private Guide guide;
// 부모 엔티티
@Entity
@Table(name = "guide", catalog = "helloworld")
public class Guide implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 9017118664546491038L;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;
@Column(name = "name", length = 45)
private String name;
@Column(name = "salary", length = 45)
private String salary;
@OneToMany(mappedBy = "guide", orphanRemoval=true)
private Set<Student> students = new HashSet<Student>(0);
이 시나리오에서 관계는 학생 실체가 관계의 소유자가되므로 전체 객체 그래프를 유지하기 위해 학생 실체를 저장해야합니다.
Guide guide = new Guide("John", "$1500");
Student s1 = new Student(guide, "Roy","ECE");
Student s2 = new Student(guide, "Nick", "ECE");
em.persist(s1);
em.persist(s2);
여기서 우리는 동일한 안내서를 두 개의 다른 학생 객체와 매핑하고 CASCADE.PERSIST를 사용하기 때문에 객체 그래프가 데이터베이스 테이블에 다음과 같이 저장됩니다 (내 경우에는 MySql)
학생 테이블 :-
1 로이 ECE 1
2 닉 ECE 1
요한 일서 $ 1500
이제 학생 중 한 명을 제거하려면
Student student1 = em.find(Student.class,1);
em.remove(student1);
학생 레코드가 제거되면 해당 가이드 레코드도 제거해야합니다. 여기서 학생 엔터티의 CASCADE.REMOVE 속성이 표시되고 그 역할은 수행됩니다. 식별자가 1 인 학생과 해당 가이드 개체 (식별자)가 제거됩니다. 1). 그러나이 예제에는 동일한 안내서 레코드에 맵핑되는 하나 이상의 학생 오브젝트가 있으며, Guide Entity에서 orphanRemoval = true 속성을 사용하지 않으면 위의 제거 코드가 작동하지 않습니다.