반응형

Cascade란?

  • cascade 옵션이란 @OneToMany나 @ManyToOne에 옵션으로 줄 수 있는 값이다.
  • Entity의 상태 변화를 전파시키는 옵션이다.
  • 만약 Entity의 상태 변화가 있으면 연관되어 있는(ex. @OneToMany, @ManyToOne) Entity에도 상태 변화를 전이시키는 옵션이다.
  • 기본적으로는 아무 것도 전이시키지 않는다.

Entity의 상태

  1. Transient
  • 객체를 생성하고 값을 주어도 JPA나 hibernate가 그 객체에 관해 아무것도 모르는 상태. 즉, 데이터베이스와 매핑된 것이 아무것도 없다.
  1. Persistent
  • 저장을 하고나서 JPA가 아는 상태(관리하는 상태)가 된다. 그러나 .save()를 했다고 해서 바로 DB에 데이터가 들어가는 것이 아니다. JPA가 persistent 상태로 관리하고 있다가 후에 데이터를 저장한다.(1차 캐시, Dirty Checking(변경사항 감지), Write Behind(최대한 늦게, 필요한 시점에 DB에 적용)등의 기능을 제공한다)
  1. Detached
  • JPA가 더이상 관리하지 않는 상태. JPA가 제공해주는 기능들을 사용하고 싶다면 다시 persistent 상태로 돌아가야한다.
  1. Removed
  • JPA가 관리하는 상태이긴 하지만 실제 commit이 일어날 때 삭제가 일어난다.

사용 예제

ex) Post(1) : Comment(N) 관계

게시글이 존재하고 해당 게시물에 달린 댓글들은 만약 이 게시글이 저장되거나 삭제되면 같이 저장되거나 삭제되어야 한다고 가정한다.

-> 이 상태로 실행하면 post만 저장해주었기 때문에 post 테이블에만 데이터가 저장된다.

여기서 Post 객체에 cascade 옵션을 주면 comment도 같이 저장이된다.

-> Post라는 인스턴스가 Transient에서 Persistent 상태로 넘어갈 때 child 객체(Comment)도 같이 Persisten 상태가 되면서 같이 저장이 되는 것이다.

cascade remove옵션도 주고나서 삭제하면 게시글을 지우면 댓글들도 같이 삭제된다.

일반적으로는 CascadeType.ALL 옵션을 줘서 사용한다.

반응형

'개발 > JPA' 카테고리의 다른 글

[JPA] @MappedSuperclass  (0) 2023.09.10
[Spring] NativeQuery  (0) 2023.09.10
[JPA] @OneToMany orphanRemoval  (0) 2023.09.10
[JPA] @OneToMany 단방향 매핑의 단점  (0) 2023.09.10
JPA 무한 재귀 해결방법  (0) 2023.09.10
반응형

orphanRemoval

  • JPA 2.0 이상에서 지원하는 것으로 ORM 스팩, JPA 레벨에서의 정의입니다.
  • orphanRemoval은 @OneToMayn 연관에서 부모 엔티티의 컬렉션 등에서 자식 엔티티가 삭제될 때 참조가 끊어지므로 DB 레벨에서도 삭제되고 @OneToOne 연관에서 엔티티가 삭제될 때 연관된 엔티티 참조가 끊어지므로 DB에서 삭제된다. 즉 참조, 연결이 끊어진(Disconnected된) 엔티티를 같이 삭제하라는 의미로 Owner 객체와 참조가 끊어진 객체들을 정리할 때 유용하다.

ex)

@Entity
class Team{
    @OneToMany(orphanRemoval=true)
    private List<Member> members;
}
반응형

'개발 > JPA' 카테고리의 다른 글

[Spring] NativeQuery  (0) 2023.09.10
[JPA] Cascade  (1) 2023.09.10
[JPA] @OneToMany 단방향 매핑의 단점  (0) 2023.09.10
JPA 무한 재귀 해결방법  (0) 2023.09.10
JPA 주요속성(@JoinColumn, @MaynToOne, @OneToMany)  (0) 2023.09.10
반응형

단점

  1. 엔티티가 관리하는 외래 키가 다른 테이블에 있음 -> 작업한 Entity가 아닌 다른 Entity에서 쿼리문이 나가는 경우가 있어 헷갈림
  2. 불필요한 쿼리문이 발생(update 등..)
  3. join table 문제

객체 저장시 update 쿼리문 추가 발생

  • Team(1) : Member(N) 구조를 가지는 테이블로 비교하겠습니다.
  • Team Entity에서 @OneToMany로 단방향을 가지는 구조입니다.

ex) Entity

ex) 2개의 member를 저장하는 코드

-> 실행 결과

member에 팀을 세팅해주는 2번의 update 쿼리가 추가로 발생함
만약 @ManyToOnE의 관계였다면 member 객체가 team을 가지고 있는 구조였다면 발생하지 않습니다.(외래키를 member가 직접 관리하기 때문에)

ex) team에 속한 member 삭제

members에서 member를 제거 했으니 해당 member에 team_id를 null로 만드는 update쿼리가 날라가는게 당연하고 memberRepository로 member를 제거했으니 delete 쿼리가 날라가는게 당연합니다.

@OneToMany 양방향

-> 위의 내용 수행 결과

ex) Team의 @OneToMany에 orphanRemoval과 cascade설정을 다음과 같이 해줍니다.

members에서 member를 삭제해주기만해도 memberRepository와 연동되어 자동으로 member를 삭제해줍니다.

반응형

'개발 > JPA' 카테고리의 다른 글

[JPA] Cascade  (1) 2023.09.10
[JPA] @OneToMany orphanRemoval  (0) 2023.09.10
JPA 무한 재귀 해결방법  (0) 2023.09.10
JPA 주요속성(@JoinColumn, @MaynToOne, @OneToMany)  (0) 2023.09.10
JPA 지연로딩(LAZY) 즉시로딩(EAGER)  (0) 2023.09.10
반응형

@JsonManagedReference와 @JsonBackReference 어노테이션 사용

  • Jackson 2.0 버전 이전에 순환 참조를 해결하기 위해 사용했던 어노테이션입니다.
  • @JsonManagedReference
    • 양방향 관계에서 정방향 참조할 변수에 어노테이션을 추가하면 직렬화에 포함된다.
  • @JsonBackReference
    • 양방향 관계에서 역방향 참조로 어노테이션을 추가하면 직렬화에서 제외된다.

Customer 객체에서 Order 객체에 @JsonManagedReference를 추가하고 Order에서는 Customer 객체에 @JsonBackReference 어노테이션을 추가하여 직렬화에서 Customer 객체를 제외 시켰습니다.

@Setter
@Getter
@ToString
public class Customer {
    private int id;
    private String name;
    @JsonManagedReference //serialized될 때 포함됨
    private Order order;
}

@Setter
@Getter
@ToString(exclude = "customer”) //toString() 실행시에도 무한 재귀가 발생하여 제외시킨다
public class Order {
    private int orderId;
    private List<Integer> itemIds;
    @JsonBackReference //serialization에서 제외된다
    private Customer customer;
}

@Test
public void infinite_recursion_해결책_JsonManagedReference_JsonBackReference() throws JsonProcessingException {
    Order order = new Order();
    order.setOrderId(1);
    order.setItemIds(List.of(10, 30));

    Customer customer = new Customer();
    customer.setId(2);
    customer.setName("Frank");
    customer.setOrder(order);
    order.setCustomer(customer);

    log.info("customer(toString) : {}", customer);
    log.info("customer(serialized json) : {}", objectMapper.writeValueAsString(customer));
    log.info("order(serialized json) : {}", objectMapper.writeValueAsString(order)); //customer정보는 제외된다
}

실행 화면

@JsonBackReference 어노테이션 선언으로 Order 객체에서 Customer 객체에 대한 정보는 빠지게 됩니다.

@JsonIdentityInfo - 추천 방식

  • Jackson 2.0 이후부터 새롭게 추가된 어노테이션입니다. @JsonIdentityInfo 어노테이션을 추가해서 직렬화에 포함 시킬 속성 값을 'property' 속성에 지정합니다.
  • @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
    • generator = ObjectIdGenerators.PropertyGenerator.class 클래스는 순환 참조시 사용할 Id를 생성하는데 사용되는 클래스이다.
  • @JsonIdentityInfo(property="id")
    • property 속성은 해당 클래스의 속성 이름을 지정한다.
    • 예제에서는 id는 Customer#id를 가리키고 직렬화/역직렬화 할 때 Order#customer의 역참조로 사용된다.

@JsonIgnore

제일 간단하게 해결할 수 있는 방법은 직렬화 할 때 순환 참조 되는 속성에 @JsonIgnore 어노테이션을 추가하여 직렬화에서 제외시키는 방법입니다.

@JsonIgnore
private Customer customer;

해당 customer 필드는 직렬화에서 제외되어 json 형태에 표시되지 않습니다.

반응형
반응형

@JoinColumn

  • 외래 키를 매핑할 때 사용한다.
속성 설명 기본 값
name 해당 Entity에서 매핑할 외래 키 이름 필드명 +_+ 참조하는 테이블의 기본 키 컬럼명
referencedColumnName 외래 키가 참조하는 대상 테이블의 컬럼명 참조하는 테이블의 기본 키 컬럼명
foreignKey(DDL) 외래 키 제약조건을 직접 지정할 수 있다. 이 속성은 테이블을 생성할 때만 사용한다.  
unique, nullable, insertable, updatable, columnDefinition, table @Column의 속성과 같다.  

@ManyToOne

  • 다대일 관계 매핑
속성 설명 기본 값
optional false로 설정하면 연관된 엔티티가 항상 있어야 한다. true
fetch 글로벌 패치 전략을 설정한다. @ManyToOne=FetchType.EAGER, @OneToMany=FetchType.LAZY
cascade 속성 전이 기능을 사용한다.  
targetEntity 연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있다.  

@OneToMany

  • 다대일 관계 매핑
속성 설명 기본 값
mappedBy 연관관계의 주인 필드를 선택한다.  
fetch 글로벌 패치 전략을 설정한다. @ManyToOne=FetchType.EAGER, @OneToMany=FetchType.LAZY
cascade 속성 전이 기능을 사용한다.  
targetEntity 연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있다.  
반응형

+ Recent posts