Spring

프록시와 연관관계 관리

yougeun 2023. 3. 23. 00:01
728x90

프록시

(1) 프록시는 실제클래스를 상속받아서 만들어지므로 타입 체크 시 instance of를 사용해야 한다

(2) 프록시 객체는 실제객체의 참조를 보관했다가 호출되면 실제객체의 메서드를 호출한다.

(3) 프록시 객체는 처음 사용할 때 한번만 초기화 되며 초기화 될 때 실제 엔티티로 바뀌는 것이아니라 프록시 객체를 통해서 실제 엔티티에 접근 가능하다.

(4) 영속성 컨텍스트에 프록시가 찾는 엔티티가 있으면 실제엔티티가 반환된다.

(5)  찾는 엔티티가 영속성컨텍스트의 도움을 받을 수 없는 준영속 상태일 때 프록시를 초기화하면 예외가 발생한다.

연관관계관리

즉시로딩

public class TeamMember {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_MEMBER_ID")
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
   ...
   }
Team team = new Team();
team.setName("teamA");
em.persist(team);

TeamMember teamMember = new TeamMember();
teamMember.setName("memberA");
teamMember.setTeam(team);
em.persist(teamMember);

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

TeamMember findMember = em.find(TeamMember.class, teamMember.getId());

즉시로딩인 경우 팀 멤버 조회시 SQL

@ManyToOne,@OneToOne의 기본전략

위의 예로보면 TeamMember가 조회되면 즉시로딩으로 설정된 Team도 같이 조회된다.

즉시 로딩을 사용하면 예상하지 못한 SQL이 발생한다.

JPQL사용 시 N+1 문제를 일으킨다.

 

 

지연로딩

public class TeamMember {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_MEMBER_ID")
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
   ...
}
Team team = new Team();
 team.setName("teamA");
em.persist(team);

TeamMember teamMember = new TeamMember();
teamMember.setName("memberA");
teamMember.setTeam(team);
em.persist(teamMember);

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

TeamMember findMember = em.find(TeamMember.class, teamMember.getId());
System.out.println("=======================");
System.out.println(findMember.getTeam().getName());
System.out.println("=======================");

지연로딩인 경우 팀멤버 조회시 SQL

@OneToMany,@ManyToMany의 기본전략

위의 예로보면 Member가 조회되면 지연로딩으로 설정된 Team은 프록시로 조회된다.

실제 Team을 사용하는 시점에 프록시가 초기화되며 프록시가 Team에 접근가능해진다.

 

영속성 전이

특정엔티티를 영속화할 때 연관된 엔티티도 함께 영속상태로 만들 때 사용한다.

종류

(1) CascadeType.ALL:모든 Cascade 적용

(2) CascadeType.PERSIST:엔티티를 영속화할 때, 연관된 엔티티도 영속화

(3) CascadeType.REMOVE:엔티티를 제거할 때, 연관된 엔티티도 제거

(4) CascadeType.MERGE:엔티티상태를 병합할 때, 연관된 엔티티도 병합

(5) CascadeType.REFRESH:엔티티를 새로고침할 때, 연관된 엔티티도 새로고침

(6) CascadeType.DETATCH:엔티티를 detach()할 때 연관된 엔티티도 detach()

 

고아 객체 제거(orphanRemoval=true)

@Entity
public class Parent {
    
    @Id
    @GeneratedValue
    private long id;
    
    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> childs;

}

Parent parent = em.find(Parent.class, parentId);
parent.getChilds().remove(childObject); // 실제 데이터베이스에서 삭제

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제

특정엔티티가 자식엔티티를 개인 소유할 때 사용

@OneToOne,@OneToMany일 때만 가능

 

CaCadeType.ALL+orphanRemoval=true

Parent parent = em.find(Parent.class, parentId);

parent.getChilds.add(child); // 자식을 저장하려면 부모에 등록만 하면된다.
parent.getChilds().remove(ChildObject);// 자식을 삭제하려면 부모에서 제거하면 된다.

이 두 옵션을 활성화하면 부모엔티티를 통해서 자식의 생명주기를 관리할 수 있다.

 

 

 

728x90