2021 08 17
2021-08-17¶
Cascade¶
- 참고 1: https://yusang.tistory.com/103
- 참고 2: https://blog.ycpark.net/entry/FOREIGN-KEY-%EC%99%80-CONSTRAINT-%EC%9D%98-%EC%82%AC%EC%9A%A9
- 참고 3: https://xlffm3.github.io/database/constraint-cascade/
- 참고 4: https://joont92.github.io/jpa/CascadeType-PERSIST%EB%A5%BC-%ED%95%A8%EB%B6%80%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0/
- 참조 무결성? - DB 모델에서 2개의 관련있는 관계 변수간의 일관성 - "주어진 속성 집합에 대해 한 관계에 나타나는 값이 다른 관계에서 특정 속성 집합에 대해서도 나타나도록 보장할 것" - PK와 FK간의 관계가 항상 유지되도록 보장하는 것! - 입력하는 자료에 대해 제약/규칙 정할 수 있음
- 제약조건? - 결점 없이 정확하고 유효한 데이터가 데이터베이스에 저장될 수 있도록 하기 위하여 - 제약조건을 건다 == 사용자가 원하는 데이터만 걸러내도록 조건을 만드는 것 - NOT NULL - UNIQUE - PK - FK - CHECK: 기본연산자/비교연산자 등을 통해 조건 확인
- DB에서 Cascade? - 참조 무결성이 깨지는 것을 허용하면서 관련된 모든 값을 업데이트하거나 삭제! - 참조 무결성이 깨지지 않도록 자동으로 값 생성하거나, 삭제하도록 도와줌 - CASCADE 옵션은 부모 테이블과 자식 테이블 간에 참조 설정 - 제약 조건을 활용하여 부모 테이블의 데이터가 삭제/변경 시 오류가 아닌 자식 테이블인 comments 테이블의 데이터에도 적용 - ON DELETE CASCADE - ON UPDATE CASCADE - 다른 테이블과 PK또는 FK로서의 관계가 여전히 존재한다면, PK가 존재하는 테이블을 맘대로 제거/비활성화 할 수 없다 - 부모 테이블 ~ 자식 테이블간의 참조 설정이 있다면, 부모 제약 조건 비활성화 & 이를 참조중인 자식 테이블 제약 조건 비활성화 하기 위함
- JPA에서 Cascade? - Cascade 옵션: "엔티티의 상태" 변화를 전파시키는 옵션 - OneToMany, ManyToOne으로 양방향 관계를 맺는 엔티티의 상태 변화 전이에 사용 - "엔티티의 상태" 1. Transient: 객체 생성하고, 값 줘도 JPA나 hibernate가 그 객체 암것도 모르는 상태 2. Persistent: 저장 하고나서 JPA가 관리하는 상태 3. Detached: JPA가 더 이상 관리 X 4. Removed: JPA가 관리하긴 하는데, 실제 commit 일어날떄 삭제됨 - CascadeType - ALL: 상위 엔티티에서 하위 엔티티로 모든 작업을 전파 - PERSIST: 하위 엔티티까지 영속성 전달 (부모 저장시 자식도 저장) - MERGE: 하위 엔티티까지 병합 작업 지속 (업데이트? ON UPDATE CASCADE 인가?) - REMOVE: 하위 엔티티까지 제거 작업 지속 (ON DELETE CASCADE 인듯) - REFRESH: DB로 부터 인스턴스 값을 다시 읽어오기 - DETACH: 영속성 컨텍스트에서 엔티티 제거
- CascadeType.PERSIST
- flush가 발생할 때 CascadeType.PERSIST가 있다면 자식에 연쇄적으로 persist operation 발생
- persist operation
- 만약 X가 새로운 엔티티라면, flush operation의 결과로 X는 데이터베이스에 트랜잭션 커밋 시점에 들어간다. - 만약 X가 이미 존재하는 엔티티라면, persist operation에서 무시된다.- 예상치 못한 동작 1
class Member{ // ... @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST) private List<Order> orderList = new ArrayList<>(); } class Order{ // ... @ManyToOne @JoinColumn(name = "member_id") private Member member; } public void deleteTest(){ Member member = em.find(Member.class, 1); List<Order> orderList = member.getOrderLsit(); for(Order order : orderList){ em.remove(order); } }- 이 경우 flush시에 orderList에 남아있는 모든 order에 대해 persist 연산을 수행 - delete 메서드가 안날라감 - 따라서 CascadeType.PERSIST를 사용하려면, 삭제하려는 order에 맞춰 orderList에서 요소 삭제하거나 - orphanRemoval = true를 줘서 삭제시 자동 delete 되게 해야함- 예상치 못한 동작 2
java @Entity class Member{ // ... @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List<Order> orders; } @Entity class Item{ // ... @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) private List<Order> orders; } @Entity class Order{ // ... @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nane = "item_id") private Item item; } Member member = em.find(Member.class, 1); List<Order> orders = member.getOrders(); for(Order order : orders){ Integer size = order.getItem().getOrders().size(); // ... } member.getOrders().clear(); // expecting delete operation- 영속성 컨텍스트에 item의 order 요소들이 올라감 - member의 orders를 비워 delete 연산을 수행하려해도, item의 orders 요소들이 남아있어 PERSIST 연산 수행됨 - delete 씹힘!
- CascadeType.MERGE
class Member{ @OneToMany(mappedBy = "member", cascade = CascadeType.MERGE) private List<Order> orderList = new ArrayList<>(); } Member member = new Member(); Order order1 = new Order(); Order order2= new Order(); member.addOrder(order1); member.addOrder(order2); member = em.merge(member); Order order3 = new Order(); member.addOrder(order3); // order1, order2 insert 됨- CascadeType.MERGE는 flush랑 관련없다네...? - em.merge 메서드에 전달한 엔티티까지만 연쇄적으로 merge가 된대 - DB에서 merge가 뭐야?
- DB에서 Merge? - 조건에 따라서 데이터의 삽입/갱신/삭제 작업한번에
- hibernate? - ORM 프레임워크 - 레드햇이 만든 ORM 프레임워크 - JPA 가이드라인의 구현체 - JPA 프로바이더임
- JPA? - 이건 그냥 구현체가 아니라 명세일뿐이야