인프런 커뮤니티 질문&답변

감바스님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

주문 서비스 개발

양방향 @OneToOne 조회에 대해 질문 있습니다.

해결된 질문

작성

·

53

0

@Entity
public class Delivery {

    @Id
    @Column(name = "delivery_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "delivery")
    private Order order;

    private Address address;

    @Enumerated(EnumType.STRING)
    private DeliveryStatus status;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public DeliveryStatus getStatus() {
        return status;
    }

    public void setStatus(DeliveryStatus status) {
        this.status = status;
    }
}
@Entity
@Table(name = "orders")
public class Order {

    @Id
    @Column(name = "order_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;

    private LocalDateTime orderDate;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Delivery getDelivery() {
        return delivery;
    }

    public void setDelivery(Delivery delivery) {
        this.delivery = delivery;
    }

    public LocalDateTime getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(LocalDateTime orderDate) {
        this.orderDate = orderDate;
    }

    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }
}
public class Test2 {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        try {
            tx.begin();

            Delivery delivery = new Delivery();
            delivery.setStatus(DeliveryStatus.READY);
            delivery.setAddress(new Address("city", "street", "zipcode"));
            em.persist(delivery);
            Order order = new Order();
            order.setOrderDate(LocalDateTime.now());
            order.setStatus(OrderStatus.ORDER);
            order.setDelivery(delivery);
            em.persist(order);

            // Order 에 fetch = FetchType.LAZY 설정 , delivery 실제 값 사용
            {
                em.flush();
                em.clear();
                Order findOrder = em.find(Order.class, order.getId());
                Delivery findDelivery = findOrder.getDelivery();
                System.out.println("findDelivery : " + findDelivery.getStatus());
            }

            tx.commit();
        }finally {
            em.close();
        }
    }

}

실행결과

Hibernate: 
    /* insert for
        com.mycom.myapp.ex.Delivery */insert 
    into
        Delivery (city, street, zipcode, status) 
    values
        (?, ?, ?, ?)
Hibernate: 
    /* insert for
        com.mycom.myapp.ex.Order */insert 
    into
        orders (delivery_id, orderDate, status) 
    values
        (?, ?, ?)
Hibernate: 
    select
        o1_0.order_id,
        o1_0.delivery_id,
        o1_0.orderDate,
        o1_0.status 
    from
        orders o1_0 
    where
        o1_0.order_id=?
Hibernate: 
    select
        d1_0.delivery_id,
        d1_0.city,
        d1_0.street,
        d1_0.zipcode,
        d1_0.status 
    from
        Delivery d1_0 
    where
        d1_0.delivery_id=?
Hibernate: 
    select
        o1_0.order_id,
        o1_0.delivery_id,
        o1_0.orderDate,
        o1_0.status 
    from
        orders o1_0 
    where
        o1_0.delivery_id=?
findDelivery : READY

강의에서 진행한 Order와 Delivery를 가지고 조회 테스트를 해봤습니다. 우선 Order와 Delivery를 양방향으로 OneToOne 관계를 설정했습니다. 그리고 둘다 각각 지연로딩으로 설정했습니다.

em.flush();
em.clear();
Order findOrder = em.find(Order.class, order.getId());
Delivery findDelivery = findOrder.getDelivery();
System.out.println("findDelivery : " + findDelivery.getStatus());

그리고 이 부분에 대해 아래와 같이 이해를 했습니다.

맨처음 em.find()를 해서 Order에 대해 DB에 select문을 보냅니다. 이때 delivery와는 지연로딩이므로 추가 select가 발생하지 않습니다.

그리고 findDelivery.getStatus()); 에서 delivery의 실제 값을 사용하므로 이때 delviery에 대한 select문이 발생합니다. 정리하면 처음에는 order에 대한 select문 그리고 실제 delevery 값을 사용할때 delivery에 대한 select문 해서 총 두번의 select문이 발생할꺼라고 예상을 했습니다.

근데 실제 실행결과를 보니 총 세번의 select문이 발생했습니다. 실행결과에서 첫번째 select문과 두번째 select문이 출력된거는 이해가 되는데 마지막 select문은 왜 발생했는지 모르겠습니다.

답변 1

0

안녕하세요. 감바스님, 공식 서포터즈 y2gcoder입니다.

마지막은 findDelivery 에서 order를 로딩하기 때문에 발생하는 것으로 보입니다.

@OneToOne 양방향 관계에서는 지연 로딩이 먹지 않는 경우가 발생합니다 🙂

다음 링크(클릭)을 참고해주십쇼!

 

감사합니다.

감바스님의 프로필 이미지
감바스
질문자

감사합니다!