티스토리 뷰

반응형

영속성 전이

한 개의 엔티티를 persist 할 때에 영속성 전이 설정이 되어 있는 엔티티도 자동으로 persist 해주는 것이다.

 

간단하게 Parent와 Child 객체를 예로 들면

Parent.java
@Entity
public class Parent {
    
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String name;

	@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> childList = new ArrayList<>();

    public void addChild(Child child){
        childList.add(child);
        child.setParent(this);
    }
}​

Child.java
@Entity
public class Child {
    
    @Id
    @GeneratedValue
    private Long id;

    private String name;

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

 

다음 소스코드에서 연관관계 맵핑의 값중 cascade라는것이 있다. cascade를 통해서 영속성 전이 설정을 할 수 있다.

cascade의 값으로는 다음과 같이 3개가 있다.

  • ALL: 모두 적용
  • PERSIST: 영속 - 저장할 때만 라이프 사이클을 맞추고 싶을때(ALL에서 삭제를 제외한 기능)
  • REMOVE: 삭제만 적용
Parent parent = new Parent();
Child child1 = new Child();
Child child2 = new Child();

parent.addChild(child1);
parent.addChild(child2);

em.persist(parent);
// em.persist(child1);
// em.persist(child2);

em.flush();
em.clear();

 

하지만 영속성 전이는 주의해서 사용해야 한다.

위의 예시처럼 하나의 부모가 자식을 관리할 때는 같은 라이프 사이클을 적용해 편리하다는 점이 있지만

만약 여러군데에서 사용하는 엔티티라면 삭제하고 싶지 않은 곳에서도 해당 엔티티가 삭제되기 때문에 전체적인 데이터의 정합성을 맞추기가 매우 어려워 진다.

따라서 다음과 같은 경우에만 사용하는 것이 좋다.

  1. 자식-부모의 라이프 사이클이 완전히 동일할때
  2. 단일 소유의 엔티티일때

영속성 전이를 하게 되며 고아 객체라는 개념이 생기게 된다. 이는 orphanRemoval이라는 것을 통해 설정이 가능하다.

위의 예시로는 child가 parent의 childList에서 빠질 때, 그 엔티티도 삭제되어 버리는 것이다.

Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);

마치 cascade의 REMOVE처럼 동작하게 된다.

또한, parent 하나의 객체가 없어지면 거기에 속해있던 child 객체도 모두 삭제되게 된다.

고아 객체도 영속성 전이와 같이 주의해서 사용해주어야 한다. 이 경우에도 참조하는 곳이 한 곳일 때만 사용해야 한다.

 

이 두가지 개념을 합쳐 cascade:ALL + orphanRemoval:true를 사용하면 부모 엔티티의 라이프 사이클로 자식 엔티티의 라이프 사이클까지 한번에 관리할 수 있게 된다.

마치 영속성 컨텍스트로 child는 관리하지 않은 것 같은 느낌을 준다.

 


임베디드 타입

임베디드 타입이란 엔티티에서 공통되는 속성을 가진 값들을 하나의 클래스로 분리하는 것이다.

임베디드 타입을 씀으로서 얻게 되는 이점은 재사용이 가능하며, 공통 변수로 응집도가 높아 해당 값만 사용하는 메서드를 만든다는 점에 있다.

추가적으로 엔티티를 읽는데 가독성 또한 편해진다.
@Embeddable
@Data @ToString
@EqualAndHashcode
public class Address {
    
    private String city;
    private String street;
    private String zipcode;

    public Address(){}

    public Address(String city, String street, String zipcode){
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}

위의 코드처럼 @Embeddable 어노테이션을 이용해서 임베디드 객체로 활용할 수 있는 객체를 만들 수 있다.

public class Member{

    @Embedded
    private Address homeAddress;
    // private String city;
    // private String street;
    // private String zipcode;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "city", column = @Column(name="WORK_CITY")),
                        @AttributeOverride(name = "street", column = @Column(name="WORK_STREET")),
                        @AttributeOverride(name = "zipcode", column = @Column(name="WORK_ZIPCODE"))})
    private Address workAddress;
    
}

그리고 사용시에는 @Embedded 어노테이션을 통해서 사용할 수 있다.

그리고 임베디드 타입을 여러개 사용하고 싶을때는 @AttributeOverrides를 사용해서 각각의 이름을 지정해줄 수 있다.

AttributeOverrides가 없다면 컬럼명이 곂쳐 오류가 날 수 있다.

임베디드 값의 경우에는 여러 엔티티에서 사용하게 되면 위험하다.

주소값을 공유해버리기 때문에 걷잡을 수 없는 디버깅을 하게 될 수 있다. A의 주소를 바꿨는데 B의 주소까지 바뀐다거나...

만약 같이 바뀌는 것을 의도 했다면 그건 임베디드 타입의 역할이 아니라 엔티티로써 DB로 관리해주어야 할 부분이다.
Address address = new Address();
Member member8 = new Member();
member8.setUsername("hello8");
member8.setHomeAddress(address);
member8.setWorkPeriod(new Period());
em.persist(member8);

Member member9 = new Member();
member9.setUsername("hello9");
member9.setHomeAddress(address);
member9.setWorkPeriod(new Period());
em.persist(member9);

em.flush();
em.clear();

다음처럼 address를 넣어주면 member8의 주소를 변경하는 것을 의도했는데 member9의 주소도 같이 바뀌게 된다.

따라서 Period처럼 넣을 때마다 새로운 객체를 만들어서 넣어주는 것이 올바르고,

비슷한 값을 가진다면, 얕은 복사를 통해서 새로운 주소의 객체를 만들어줘야 한다.

 

이러한 실수를 피하기 위해서는 불변객체로 임베디드 타입을 만드는 것이 좋다.(생성자로 값 주입 후, setter를 만들지 않는 것)

728x90
반응형

'Back End > JPA' 카테고리의 다른 글

[JPA 기초] 4. 프록시  (0) 2022.10.14
[JPA 기초] 3-1. @MappedSuperclass  (0) 2022.10.14
[JPA 기초] 3. 연관관계 맵핑  (0) 2022.10.14
[JPA 기초] 2. Entity - DB 맵핑  (2) 2022.10.04
[JPA 기초] 1. 영속성 컨텍스트  (0) 2022.10.03
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함
250x250