프록시와 연관관계
객체그래프 탐색
객체는 객체 그래프로 연관된 객체를 탐색한다.
Entity는 객체가 데이터베이스(RDB)와 매핑되어 있어서 자유롭개 객체를 탐색하는데 제한이 있다.
// order.getMember() → orders 테이블과 member 테이블의 정보를 모두 가져와야 하는상태.
JPA는 프록시객체라는 기술을 사용하여 연관된 객체를 처음부터 데이터베이스에서 조회하지 않고, 실제 사용하는 시점에 조회할 수 있다.
프록시 객체
@Entity @Table(name = "member") public class Member extends BaseEntity { ... @OneToMany(mappedBy = "member", fetch = FetchType.LAZY) private List<Order> orders = new ArrayList<>(); // proxy ... }
@Entity @Table(name = "orders") public class Order extends BaseEntity { ... @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", referencedColumnName = "id") private Member member; ... }
@Test void proxy() { EntityManager entityManager = emf.createEntityManager(); // 회원 조회 -> 회원의 주문 까지 조회 Member findMember = entityManager.find(Member.class, 1L); log.info("orders is loaded : {}", entityManager.getEntityManagerFactory() .getPersistenceUnitUtil().isLoaded(findMember.getOrders())); log.info("-------"); log.info("{}" ,findMember.getOrders().get(0).getMemo()); log.info("orders is loaded : {}", entityManager.getEntityManagerFactory() .getPersistenceUnitUtil().isLoaded(findMember.getOrders())); } // 실행결과 Hibernate: select member0_.id as id1_1_0_, member0_.created_at as created_2_1_0_, member0_.created_by as created_3_1_0_, member0_.address as address4_1_0_, member0_.age as age5_1_0_, member0_.description as descript6_1_0_, member0_.name as name7_1_0_, member0_.nickName as nickname8_1_0_ from member member0_ where member0_.id=? 2021-09-11 14:11:52.453 INFO 7960 --- [ main] com.kdt.lecture.domain.order.ProxyTest : orders is loaded : false 2021-09-11 14:11:52.454 INFO 7960 --- [ main] com.kdt.lecture.domain.order.ProxyTest : ------- Hibernate: select orders0_.member_id as member_i7_3_0_, orders0_.id as id1_3_0_, orders0_.id as id1_3_1_, orders0_.created_at as created_2_3_1_, orders0_.created_by as created_3_3_1_, orders0_.member_id as member_i7_3_1_, orders0_.memo as memo4_3_1_, orders0_.order_datetime as order_da5_3_1_, orders0_.orderStatus as ordersta6_3_1_ from orders orders0_ where orders0_.member_id=? 2021-09-11 14:11:52.459 INFO 7960 --- [ main] com.kdt.lecture.domain.order.ProxyTest : 부재시 전화주세요. 2021-09-11 14:11:52.459 INFO 7960 --- [ main] com.kdt.lecture.domain.order.ProxyTest : orders is loaded : true
프록시의 특징
- 프록시 객체는 처음 사용할 때 한번만 초기화 된다.
- 프록시 객체가 초기화되면, 프록시 객체를 통해서 실제 엔티티에 접근 할 수 있다.
- 초기화는 영속성 컨텍스트의 도움을 받아야 가능하다. 따라서 준영속 상태의 프록시를 초기화하면 LazyInitializationException 예외가 발생한다.
지연로딩(LAZY) & 즉시로딩(EAGER)
지연로딩
엔티티를 조회할때, 연관된 엔티티를 함께 조회한다.

즉시로딩
연관된 엔티티를 실제 사용할 때 조회한다.

영속성 전이(CASCADE)
특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속상태로 만들고 싶을때, 사용한다.
public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH; private CascadeType() { } }

고아객체
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능이다.
@Entity @Table(name = "member") public class Member extends BaseEntity { ... @OneToMany(mappedBy = "member", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private List<Order> orders = new ArrayList<>(); ... }
@Test void orphan() { EntityManager entityManager = emf.createEntityManager(); // 회원 조회 -> 회원의 주문 까지 조회 Member findMember = entityManager.find(Member.class, 1L); findMember.getOrders().remove(0); // order를 제거한다. (고아객체) EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); transaction.commit(); } // 실행결과 Hibernate: call next value for hibernate_sequence Hibernate: insert into orders (created_at, created_by, member_id, memo, order_datetime, orderStatus, id) values (?, ?, ?, ?, ?, ?, ?) Hibernate: insert into member (created_at, created_by, address, age, description, name, nickName, id) values (?, ?, ?, ?, ?, ?, ?, ?) Hibernate: update orders set created_at=?, created_by=?, member_id=?, memo=?, order_datetime=?, orderStatus=? where id=? Hibernate: select member0_.id as id1_1_0_, member0_.created_at as created_2_1_0_, member0_.created_by as created_3_1_0_, member0_.address as address4_1_0_, member0_.age as age5_1_0_, member0_.description as descript6_1_0_, member0_.name as name7_1_0_, member0_.nickName as nickname8_1_0_ from member member0_ where member0_.id=? Hibernate: select orders0_.member_id as member_i7_3_0_, orders0_.id as id1_3_0_, orders0_.id as id1_3_1_, orders0_.created_at as created_2_3_1_, orders0_.created_by as created_3_3_1_, orders0_.member_id as member_i7_3_1_, orders0_.memo as memo4_3_1_, orders0_.order_datetime as order_da5_3_1_, orders0_.orderStatus as ordersta6_3_1_ from orders orders0_ where orders0_.member_id=? Hibernate: delete from orders where id=?