Q) 영속성 컨텍스트란 무엇인가요?
A) 엔티티를 영구히 저장하는 환경입니다. 엔티티 매니저를 통해 영속성 컨텍스트에 접근합니다.
Q) 엔티티의 생명주기는?
A) 비영속(new) 상태는 영속성 컨텍스트와 전혀 관계없는 상태입니다.
영속(managed) 상태는 영속성 컨텍스트에 관리되는 상태입니다.
준영속(detached) 상태는 영속성 컨텍스트에 저장되었다가 분리된 상태입니다.
삭제(removed) 상태는 삭제된 상태입니다.
Q) 영속성 컨텍스트로 관리하면 어떤 장점이 있나요?
A) 1차 캐시를 통해 데이터를 캐시에서 가져올 수 있습니다. 또한 데이터의 동일성을 보장합니다.
쓰기 지연을 통해 트랜잭션을 지원합니다. 변경 감지를 통해 자동으로 update가 이루어집니다.
또 지연 로딩을 통해 성능을 높입니다.
Q) @Entity와 @Table은 무엇인가요?
A) @Entity가 붙은 클래스는 JPA가 관리하게 됩니다. 이때 클래스는 기본 생성자를 반드시 가지고 있어야 합니다.
final 클래스, enum, interface, inner 클래스에는 사용이 불가하며 저장할 필드에 final 사용이 불가능합니다.
@Table은 엔티티와 매핑할 테이블을 지정합니다.
Q) 기본키 매칭은 어떻게 이루어지나요?
A) @Id를 통해 키로 지정해줄 수 있고, @GeneratedValue를 통해 키를 자동 생성할 수 있게 합니다.
Q) N : 1 매핑은 어떻게 이루어지는 지 설명해주세요.
A) 테이블에서는 항상 N쪽 엔티티가 FK를 가지고 있습니다. 그렇기 때문에 객체에서도 N쪽 객체가 FK를 관리하도록 설계하면 좀 더 직관적이고 쉬운 관리가 가능합니다. 우선 다대일 매핑을 설정하려면 N쪽 클래스에 1쪽 객체를 만들어주고 @ManyToOne 어노테이션을 달아주어야 합니다. 그러면 JPA는 자동적으로 N쪽 엔티티 테이블에 FK를 추가해줍니다.
만약 양방향 매핑을 통해 서로 참조가 가능해지도록 하려면 1쪽에도 컬렉션 객체를 생성한 뒤 @OneToMany 어노테이션을 설정해줍니다. 이때 연관관계 주인이 아니라는 의미로 mappedBy 속성을 지정해주어야 합니다.
+) 예시: Member 객체와 Team 객체
Member 클래스 안에 @ManyToOne Team team;
Team 클래스 안에 @OneToMany(mappedBy="team") List<Member> members = new ArrayList<>();
Q) 1 : N 매핑은 어떻게 이루어지는 지 설명해주세요.
A) 일대다 매핑는 1쪽 클래스에 @OneToMany 어노테이션을 설정해줄 수 있습니다. 이렇게 되면 1쪽에서 FK를 관리하게 되는데, 테이블은 여전히 N쪽 엔티티에서 FK를 관리하는 구조로 되어있기 때문에 이 경우 1쪽 객체가 다른 테이블에 관여하게 되는 상황이 발생합니다. 실제로 1쪽 객체의 컬렉션 안에 객체를 추가하게 되면 1쪽 엔티티의 값을 업데이트하는 업데이트 쿼리가 나가게 되는데 이는 다대일 매핑에 비해 비효율적일 수 있습니다.
+) 예시: Member 객체와 Team 객체
Team 클래스 안에 @OneToMany List<Member> members = new ArrayList<>();
이때 team.getMembers().add(member);를 해주게 되면 Member 엔티티를 업데이트해주기 위해 업데이트 쿼리가 나갑니다.
Q) 상속 관계 매핑은 어떻게 설정하나요?
A) 클래스 상속 관계는 테이블 슈퍼-서브 타입 관계와 유사합니다.
상속 관계 매핑은 슈퍼타입 객체에 Inheritance 어노테이션을 설정하면 됩니다. DTYPE 추가를 위해선 @DiscriminaterColumn을 추가해줍니다. 상속 관계 매핑 시에는 여러 전략을 선택할 수 있는데,
JOIN 전략은 상속받는 엔티티를 각각 테이블로 만들어줍니다. 이 전략은 테이블이 정규화되어 있다는 장점이 있지만, 조회 시 조인으로 인해 성능 저하의 우려가 있습니다.
단일 테이블 전략은 통합 테이블을 만듭니다. 조회 쿼리가 단순하고 조인이 필요없어 조회 성능이 빠르다는 장점을 가집니다. 하지만 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있어 이로 인해 성능 저하가 생길 수 있습니다. 또 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 합니다.
Q) @MappedSuperclass는 무엇인가요?
A) 상속 관계와는 관계없고, 여러 엔티티가 공통으로 사용하는 매핑 정보를 묶어주는 역할을 합니다. 클래스를 직접 생성해서 사용할 일이 없으므로 보통 추상 클래스에 사용합니다.
Q) 프록시와 지연 로딩에 대해 설명해주세요.
A) 프록시란 대리 역할을 수행하는 가짜 객체를 의미합니다. 프록시는 데이터베이스 조회를 미루는 가짜 엔티티를 조회합니다. 지연 로딩을 사용하게 되면 em.find 수행 시 일단 프록시로 조회를 하고, 실제 객체를 사용하는 시점에 db를 통해 초기화합니다. 이렇게 하면 사용하지 않는 정보를 굳이 조회하지 않아도 된다는 장점이 생깁니다.
반대 개념인 즉시 로딩은 특정 엔티티 조회 시 연관된 모든 엔티티 정보를 조회합니다.
+) @ManyToOne이나 @OneToOne 같이 xToOne의 경우 기본 설정이 즉시 로딩으로 설정되어 있기 때문에, 이때는 fetch 설정을 FetchType.LAZY로 해주는 것이 좋습니다. 즉시 로딩은 예상치 못한 SQL을 발생시키고, N+1 문제를 일으키기 때문입니다.
Q) 영속성 전이(CASCADE)는 무엇인가요?
A) 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들 수 있는 기능입니다.
@OneToMany(cascade=CascadeType.PERSIST)와 같이 설정할 수 있습니다.
Q) 고아 객체는 무엇인가요?
A) 고아 객체를 설정하면 부모 엔티티와 연관 관계가 끊어진 자식 엔티티를 자동으로 삭제해줍니다. 참조하는 곳이 하나일 때 사용해야 하므로 @OneToOne이나 @OneToMany와 같이 @OneToX일때만 사용할 수 있습니다.
+) 영속성전이와 고아 객체를 함께 사용하면 부모 엔티티가 자식 엔티티의 생명주기를 관리할 수 있게 됨
Q) 임베디드 값 타입은 무엇인가요?
A) 기본 값 타입들을 모아 복합적인 값 타입을 만든 것입니다.
값 타입을 정의하는 곳엔 @Embeddable을, 사용하는 곳엔 @Embedded 어노테이션을 달아줍니다. 이때 기본 생성자를 필수로 가져야 합니다. 임베디드 타입의 장점은 재사용이 쉽고 높은 응집도를 가지기 때문에 해당 값 타입만으로 의미있는 메서드를 만들 수 있습니다.
댓글