-
@Entity - 이 클래스를 테이블과 매핑한다고 Jpa에게 알려준다.
-
@Table - 엔티티클래스에 매핑할 테이블 정보를 알려준다.
-
@Id - 기본 키(primary key)에 매핑한다.
-
@Column - 필드를 칼럼에 매핑
-
@ManyToOne, @JoinColumn - 연관관계 매핑
-
JPA를 사용 시 문제는 검색 쿼리에서 발생
- 이때 사용되는것이JPQL JPQL은 엔티티객체를 대상으로 쿼리한다(SQL은 데이터베이스 테이블을 대상으로 쿼리한다)
- 영속성 컨텍스트란?
- 엔티티를 영구 저장하는 환경
- 예로 persist()메소드는 엔티티 매니저를 사용해서 회원엔티티를 영속성 컨텍스트에 저장한다.
- 엔티티 생명주기
- 비영속 - 영속성 컨텍스트와 관계없는 상태
- 영속 - 영속성 컨텍스트에 저장된 상태( 영속성 컨텍스트에 의해 관리된다)
- 준영속 - 영속성 컨텍스트에 저장되어있다가 분리된 상태
- 삭제 - 삭제된 상태
- 영속성 컨텍스트 특징
- 영속 상태는 식별자 값이 반드시 있어야한다.
- JPA는 트랜잭션에 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영(플러시))
- 장점
- 1차캐시
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
- CASCADE - 특정 엔티티를 영속상태로 만들 때 연관된 엔티티도 함꼐 영속 상태로 만들떄 사용
- 영속성 전이를 사용하면 부모 엔티티를 저장할때 자식엔티티도 함꼐 저장할 수 있다.
- JPA에서 엔티티를 저장할 떄 연관된 모든 엔티티는 영속상태여야 한다.
- 예) @OneToMany(mappedBy = “parent”, cascade - CascadeType.PERSIST) - 부모를 영속화 할떄 연관된 자식도 함께 영속
- 저장한 부모와 자식 엔티티를 모두 제거하려면 각각의 엔티티를 하나씩 제거해야 한다.
- 예) em.remove(findChild1); / em.remove(findChild2); / em.remove(findChild3); / em.remove(findParent);
- 만약 CascadeType.REMOVE를 설정하지않고 이코드를 실행하면 부모엔티티만 삭제되는데 부모로우를 삭제하는 순간 자식테이블에 걸려있는 외래키 제약조건을 인해 DB에 외래키 무결성 예외가 발생한다.
- CASCADE의 종류
- ALL - 모두 적용
- PERSIST - 영속
- MERGE - 병합
- REMOVE - 삭제
- REFRESH - REFRESH
- DETACH - DETACH
- 고아객체 - JPA 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로삭제하는 기능을 제공한다. 이것을 고아(ORPHAN)객체 제거라 한다.
- 예) @OneToMany(mappedBy = “parent”, orphanRemoval = true)
- 부모 엔티티의 컬렉션에서 자식엔티티의 참조만 제거하면 자식엔티티가 자동으로 삭제된다.
- 고아객체 제거는 참조가 제거된 엔티티는 다른 곳에서 참조하지않는 고아객체로 보고 삭제하는 기능이다.
- 그래서 orphanRemovla은 @OneToOne, @OneToMany에서만 사용할 수 있다.
- 영속성 전이 + 고아객체, 생명주기
- cascadeType.ALL + orphanRemoval = True 를 동시에 사용한다면?
- 일반적으로 엔티티는 EntityManager.persist()를 통해 영속화 되고 EntityManager.remove()에 의해 제거된다.
- 엔티티 스스로 생명주기를 관리한다는 뜻이다.
- 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
// 자식을 저장하려면 부모에 등록만 하면된다.(CASCADE)
Parent parent = em.find(Parent.class, parentId);
parent.addChild(child1);
// 자식을 삭제하려면 부모에서 제거하면 된다(orphanRemoval)
Parent parent = em.find(Parent.class, parentId);
parent.getChaldren().remove(removeObject);
- 영속성 전이는 DDD의 Aggregate Root개념을 구현할 때 사용하면 편하다.
- 즉시로딩(pre-Loading) - 엔티티를 조회할 떄 연관된 데이터도 함꼐 조회한다.
- 설정방법 - @ManyToOne(fetch = FetchType.EAGER)
- JPA는 즉시로딩을 최적화 하기위해 가능하면 조인 쿼리를 사용한다.
- 지연로딩(lazy-Loading) - 연관된 엔티티를 실제 사용할 떄 조회한다.
- 설정방법 - @ManyToOne(fetch = FetchType.LAZY)
- 연관된 엔티티를 프록시로 조회한다.
- fetch 전략
- 추천하는 방법은 모든 연관관계에 지연로딩을 사용하는 것이다, 개발중 필요한 곳에만 즉시로딩을 사용하도록 최적화 하는 것이 좋다.
- FetchType.EAGER 사용 시 주의점
- 컬렉션을 하나 이상 즉시 로딩하는 것은 권장하지 않는다.
- 컬렉션 즉시 로딩은 항상 외부조인을 사용한다.
- NULL 제약 조건과 JPA 조인 전략
- NULL 값을 허용하면 JPA는 이런 상황을 고려해서 외부조인을 사용한다.
- 하지만 내부조인이 성능과 최적화에서 더 유리하다, 내부조인을 사용하려면?
- NOT NULL 제약조건을 설정하면 값이 있는 것을 보장한다, 따리서 이때는 내부조인만 사용해도 된다.
-
@JoinColumn에 nullable = false 설정해서 이 외래 키는 null을 허용하지않는다고 하면 JPA는 내부조인을 사용한다.
- nullable = true : null 허용(기본값), 외부조인 사용
- nullable = false : null 허용않음, 내부조인 사용
- 또는 @ManyToOne.option = false 로 해줘도 내부조인을 사용한다.
- JPA는 선택전 관계면 외부조인을 사용하고 필수 관계면 내부 조인을 사용한다.
- 정리
- @ManyToOne, @OneToOne
- (optional = false) - 내부조인
- (optional = true) - 외부조인
- @OneToMany, @ManyToMany
- (optional = false) - 외부조인
- (optional = true) - 외부조인
- @ManyToOne, @OneToOne