프록시와 연관관계 관리
프록시
(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());
@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("=======================");
@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);// 자식을 삭제하려면 부모에서 제거하면 된다.
이 두 옵션을 활성화하면 부모엔티티를 통해서 자식의 생명주기를 관리할 수 있다.