# [JPA] μ˜μ†μ„± 전이 by Cascade μ˜΅μ…˜
Study Repository

[JPA] μ˜μ†μ„± 전이 by Cascade μ˜΅μ…˜

by rlaehddnd0422

μ˜μ†μ„± 전이

μ˜μ†μ„± μ „μ΄λŠ” νŠΉμ • μ—”ν‹°ν‹°λ₯Ό μ˜μ† μƒνƒœλ‘œ λ§Œλ“€ λ•Œ μ—°κ΄€λœ 엔티티도 ν•¨κ»˜ μ˜μ†μƒνƒœλ‘œ λ§Œλ“€κ³  싢을 λ•Œ μ‚¬μš©ν•˜λŠ” μ˜΅μ…˜μž…λ‹ˆλ‹€.

JPAλŠ” 닀쀑성 μ–΄λ…Έν…Œμ΄μ…˜(@ManyToOne, @OneToMany λ“±)에 cascade μ˜΅μ…˜μœΌλ‘œ μ˜μ†μ„± 전이λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. μ‰½κ²Œ 말해 μ˜μ†μ„± 전이λ₯Ό μ‚¬μš©ν•˜λ©΄ λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•  λ•Œ μžμ‹ 엔티티도 ν•¨κ»˜ μ €μž₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

Parent

@Entity
public class Parent {

    @Id @GeneratedValue
    @Column(name = "PARENT_ID")
    private Long id;

    @OneToMany(mappedBy = "parent")
    private List<Child> children = new ArrayList<Child>();

    public List<Child> getChildren() {
        return children;
    }
}

 Child

@Entity
public class Child {

    @Id
    @GeneratedValue
    @Column(name = "CHILD_ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;

    public void setParent(Parent parent) {
        if(this.parent == null)
        {
            this.parent = parent;
            parent.getChildren().add(this);
        }
    }
}

 

μœ„μ²˜λŸΌ Parent(1) ↔️ Children(*) 연관관계λ₯Ό κ°€μ§ˆ λ•Œ μ˜μ†μ„± μ „μ΄μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ§€ μ•Šκ³  Parent와 Child μ—”ν‹°ν‹°λ₯Ό λͺ¨λ‘ μ €μž₯ν•˜λ €λ©΄ 두 μ—”ν‹°ν‹° λͺ¨λ‘ λ‹€ μ˜μ†μƒνƒœλ‘œ 각각 λ§Œλ“€μ–΄ μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();

    try
    {
        Parent parent = new Parent();
        em.persist(parent);

        Child child = new Child();
        child.setParent(parent); // Child -> Parent
        parent.getChildren().add(child); // Parent -> Child

        em.persist(child);

        tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }
}
  • μ–‘λ°©ν–₯ 연관관계 맀핑 ν›„ Parent 엔티티도 em.persist, Child 엔티티도 em.persist 
  • ν•˜μ§€λ§Œ 여기에 μ˜μ†μ„± 전이 μ˜΅μ…˜μ„ μ‚¬μš©ν•˜λ©΄ Parent μ—”ν‹°ν‹°λ§Œ persistν•˜λ©΄ Child μ—”ν‹°ν‹°λŠ” λ”°λ‘œ persist해주지 μ•Šμ•„λ„ λ©λ‹ˆλ‹€.

cascade μ˜΅μ…˜ 적용

@OneToMany(cascade = CascadeType.PERSIST)

Parent

@Entity
public class Parent {

    @Id @GeneratedValue
    @Column(name = "PARENT_ID")
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
    private List<Child> children = new ArrayList<Child>();

    public List<Child> getChildren() {
        return children;
    }
}

 

μ €μž₯ν•˜λŠ” μ½”λ“œ

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();

    try
    {
        Parent parent = new Parent();
        em.persist(parent);

        Child child = new Child();
        child.setParent(parent); // Child -> Parent
        parent.getChildren().add(child); // Parent -> Child

        tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }
}
  • em.persist(child) 뢀뢄이 μ œκ±°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • em.persist(parent)λ₯Ό μˆ˜ν–‰ν•  λ•Œ μ˜μ†μ„± 전이 μ˜΅μ…˜μ„ μ„€μ •ν•΄λ‘μ—ˆκΈ° λ•Œλ¬Έμ— persist둜 parent μ—”ν‹°ν‹°λ₯Ό μ˜μ†ν™” ν•  λ•Œ child μ—”ν‹°ν‹°λŠ” μžλ™μœΌλ‘œ μ˜μ†ν™”κ°€ μ§„ν–‰λ©λ‹ˆλ‹€.
    • commit μ‹œμ μ— flush()둜 DB에 반영.

CASCADE μ’…λ₯˜

μ˜μ†μ„± μ „μ΄λŠ” μ‚½μž… 뿐만 μ•„λ‹ˆλΌ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ‚­μ œ, 병합, λ“± μ—¬λŸ¬κ°€μ§€ μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆλ‹€.

 

public enum CascadeType {
    ALL,
    PERSIST,
    MERGE,
    REMOVE,
    REFRESH,
    DETACH;

    private CascadeType() {
    }
}
  • ALL : λͺ¨λ‘ 적용
  • remove : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ  λ•Œ, μ—°κ΄€λœ 엔티티도 ν•¨κ»˜ μ‚­μ œ 
  • merge : μ€€μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό μ˜μ† μƒνƒœλ‘œ λ‹€μ‹œ λ³€κ²½ν•  λ•Œ μ—°κ΄€λœ 엔티티도 ν•¨κ»˜ λ³€κ²½
persist, remove μ˜΅μ…˜μ€ flush()λ₯Ό 호좜(컀밋)ν•  λ•Œ 전이가 λ°œμƒν•©λ‹ˆλ‹€.

κ³ μ•„ 객체

JPAλŠ” 연관관계가 λŠμ–΄μ§„ μ—”ν‹°ν‹°λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 이λ₯Ό κ³ μ•„ 객체 제거라고 ν•©λ‹ˆλ‹€.

고아객체 제거 κΈ°λŠ₯κ³Ό cascade μ˜΅μ…˜μ˜ remove의 차이
- κ³ μ•„ 객체 제거 κΈ°λŠ₯은 μ°Έμ‘°λ₯Ό μ œκ±°ν•˜μ—¬ 연관관계가 λŠμ–΄μ§„ μ—”ν‹°ν‹°λ§Œ μ‚­μ œ 
- cascade μ˜΅μ…˜μ˜ remove λŠ” μ˜μ†μƒνƒœμ˜ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ  λ•Œ μ—°κ΄€λœ 엔티티도 ν•¨κ»˜ μ‚­μ œ

λΆ€λͺ¨ μ—”ν‹°ν‹°μ˜ μ»¬λ ‰μ…˜μ—μ„œ μžμ‹ μ—”ν‹°ν‹°μ˜ 참쑰만 μ œκ±°ν•˜λ©΄ μžμ‹ μ—”ν‹°ν‹°κ°€ μžλ™μœΌλ‘œ μ‚­μ œλ©λ‹ˆλ‹€.

@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<Child>();
  • 닀쀑성 μ–΄λ…Έν…Œμ΄μ…˜μ˜ orphanRemoval μ˜΅μ…˜μ„ true둜 μ„€μ •ν•˜λ©΄ κ³ μ•„ 객체 제거 κΈ°λŠ₯이 μ μš©λ©λ‹ˆλ‹€.
public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();

    try
    {
        Parent parent = em.find(Parent.class, 1L);
        parent.getChildren().remove(0); // μžμ‹ μ—”ν‹°ν‹°λ₯Ό μ»¬λ ‰μ…˜μ—μ„œ 제거

        tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }
}

 

μ°Έμ‘°κ°€ 제거된 μ—”ν‹°ν‹°λŠ” λ‹€λ₯Έκ³³μ—μ„œ μ°Έμ‘°ν•˜μ§€ μ•ŠλŠ” κ³ μ•„ 객체둜 보고 μ‚­μ œν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€.

λ§Œμ•½ μ‚­μ œν•œ μ—”ν‹°ν‹°λ₯Ό λ‹€λ₯Έκ³³μ—μ„œ μ°Έμ‘°ν•œλ‹€λ©΄ λ¬Έμ œκ°€ 될 수 있기 λ•Œλ¬Έμ— 이 κΈ°λŠ₯은 μ°Έμ‘°ν•˜λŠ” 곳이 ν•˜λ‚˜μΌ λ•Œλ§Œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

즉, @OneToMany,@OneToOneμ—λ§Œ μ‚¬μš© κ°€λŠ₯.

 

+ κ³ μ•„ 객체 제거 κΈ°λŠ₯은 λΆ€λͺ¨λ₯Ό μ œκ±°ν•˜λ©΄ μžμ‹μ€ κ³ μ•„κ°€ 되기 λ•Œλ¬Έμ— Cascade.removeλ₯Ό μ„€μ •ν•œ 것과 κ°™μŠ΅λ‹ˆλ‹€.

 

Tip
CascadeType.All κ³Ό orphanRemoval 을 λͺ¨λ‘ μ μš©ν•˜λ©΄ λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό ν†΅ν•΄μ„œ μžμ‹μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό 관리할 수 있음
μžμ‹μ„ μ €μž₯ν•˜λ €λ©΄ λΆ€λͺ¨λ§Œ μ €μž₯, μžμ‹μ„ μ‚­μ œν•˜λ €λ©΄ λΆ€λͺ¨λ§Œ μ‚­μ œ

<정리>

  • 객체λ₯Ό μ €μž₯, μ‚­μ œν• λ•Œ μ—°κ΄€λœ 객체도 ν•¨κ»˜ μ €μž₯, μ‚­μ œν•˜κ³  싢은 경우 μ˜μ†μ„± 전이 κΈ°λŠ₯을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 연관관계가 λŠμ–΄μ§„ μ—”ν‹°ν‹°λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•˜λ €λ©΄ κ³ μ•„ 객체 제거 κΈ°λŠ₯을 μ‚¬μš©ν•˜λ©΄ λ˜λŠ”λ°,  μ μš©ν–ˆμ„ λ•Œ λΆ€λͺ¨ 객체λ₯Ό μ‚­μ œν•˜λŠ” 경우 μžμ‹μ€ κ³ μ•„κ°€ λ•Œλ¬Έμ— μžλ™μœΌλ‘œ μ‚­μ œ λ˜λ―€λ‘œ CascadeType.removeλ₯Ό μ μš©ν•œ 것과 동일

<참고자료>

λΈ”λ‘œκ·Έμ˜ 정보

Study Repository

rlaehddnd0422

ν™œλ™ν•˜κΈ°