<aside>

단방향 메서드, 양방향 메서드

</aside>

<aside>

연관관계 매핑의 주인(mapped By)

<aside>

@Embedded

@Embedded 
private Address address; 
@Enumerated(EnumType.STRING) 
private DeliveryStatus status; // READY, COMP } 

여기서 @Embedded로 enum값을 가져오는거랑 @Enumerated로 enum 가져오는게 무슨 차이?

@Embedded는 객체를 저장하기 위한 애노테이션 @Enumerated는 enum을 데이터베이스에 어떤 방식으로 저장할 지 지정하는 애노테이션.

</aside>

<aside>

즉시 로딩과 지연 로딩

즉시 로딩(EAGER)

지연 로딩(LAZY)

@ManyToOne(fetch = FetchType.LAZY)

즉시 로딩은 JPQL을 실행할 때 N+1가 자주 발생한다.

</aside>

<aside>

N+1 이란?

<aside>

@Transactional(readOnly = true)

@Transactional(readOnly = true)를 왜 붙여야 하나요

<aside>

EntityManager의 Dirty Checking(변경 감지)

<aside>

멀티 스레드

private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if (!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        } 
    }

이런 상황에서 memberA가 동시에 두 개 조회하고 Empty로 뜨면, 둘 다 등록 될 수도 있다. 다른 쓰레드가 끼어드는게 Race Condition.

그래서 DB의 유니크 제약 조건을 사용한다.

UNIQUE 제약 조건

@Column(unique = true)
private String name;

</aside>

<aside>

생성자 주입 vs 필드 주입

@RequiredArgsConstructor
// 생성자 주입
    // lombok이 컴파일할 때 생성자 자동 생성
    private final EntityManager em;

생성자 주입을 더 많이 사용하는 이유?

  1. final을 사용할 수 있다. private final EntityManager em; ⇒ 한 번 주입되면 바뀌지 않는다.
  2. 객체가 생성될 때 반드시 의존성이 주입된다. ⇒ 실수 줄일 수 있다.
  3. 테스트하기 쉽다. ⇒ 테스트에서 Mock을 생성자로 쉽게 넣어줄 수 있다.
// 필드 주입
    @PersistenceContext  // em을 주입해줌
    private EntityManager em;

</aside>

<aside>

em.persist 와 em.merge

public void save(Item item){
        // item은 JPA저장하기 전까지 id값이 없다.
        if (item.getId() == null){
            em.persist(item);
        } else {
            em.merge(item);
        }
    }

JPA에서 새로운 엔티티를 영속성 컨텍스트에 관리되도록 하고 데이터베이스에 저장할 때 em.persist를 사용한다.

이미 ID가 있는 엔티티를 업데이트할 때는 em.merge가 사용될 수 있.

</aside>

<aside>

가변인자

public staticOrder createOrder(Member member, Delivery delivery, OrderItem... orderItems){

}

</aside>

<aside>

@NoArgsConstructor

@NoArgsConstructor(access = AccessLevel.PROTECTED)

protected Member() {
}

<aside>

페이징

public List<Order> findAll(OrderSearch orderSearch) {
        return em.createQuery("select o from Order o join o.member m" +
                            " where o.status = :status " +
                            " and m.name like :name ", Order.class)
                .setParameter("status", orderSearch.getOrderStatus())
                .setParameter("name", orderSearch.getMemberName())
                .setMaxResults(1000)
                .getResultList();
    }

<aside>

</aside>

<aside>

</aside>