Jpa-프록시, 값 타입, 객체지향 쿼리 언어
fetch, cascade
- 프록시란? (→ 결국 지연로딩을 위함)
- 엔티티를 조회할 때 연관관계가 있는 엔티티를 항상 사용하는건 아니다.
- Member에 있는 name(String)이나 id(Long)은 바로 쓰이는데 team(Team)이란 필드는 조회안하면 Member를 조회할 때 Team을 조회할 필요가 없다. 그래서 Member를 조회할 때 가짜객체인 프록시객체를 만들어 잠깐 실제 Team객체 불러오는걸 지연 해놓고 진짜 team필드가 쓰일 때(team.getName()) 프록시를 통해 실제 객체를 불러와서 쓴다. 이게 프록시의 대충 이해한 개념이다.
- 프록시 초기화란?
- 영속성 컨텍스트에 요청이 들어온 실제 엔티티가 없을 때 실제 엔티티 생성을 요청하는 것.
- 누가? 프록시 객체가.
- 프록시가 초기화되지 않는 경우
- 이미 영속성컨텍스트에 해당 엔티티가 올라와져있을 때 → 걍 실제 객체를 가져온다.
- 식별자(Id)를 조회할 때는 받았던 파라미터를 그대로 출력한다.
- 영속상태가 아닐 경우엔 프록시초기화가 안된다.
- 지연로딩에서 쓰이는게 프록시
- 지연로딩(FetchType.LAZY) vs 즉시로딩(FetchType.EAGER)
- 상황에 따라 선택이 바뀐다. 회원과 팀 엔티티가 대부분의 어플리케이션 로직에서 같이 쓰인다면 둘은 그냥 즉시로딩으로 설정해놓는 것이 편하다.
- 하지만 가끔씩 조회하기위해 참조를 쓰는 곳이면 지연로딩을 하는것이 효율적이다.
- 보통 @OneToMany의 필드인 컬렉션을 로딩하는건 지연로딩하는걸 권장한다.
- 추천방법 : 처음엔 전부 지연로딩으로 했다가 개발이 완료단계에 왔을 때 실제 사용하는 상황을 보고 필요한 곳에만 즉시로딩을 사용해서 최적화시키면 된다.
-
선택적 관계면 외부조인 (optional=true), 필수적 관계면 내부조인 (optional=false)
- 영속성 전이
- 엔티티를 영속화할 때 연관된 엔티티도 같이 영속화 하거나 영속관계를 끊을 때 자동으로 연관관계의 엔티티의 영속성을 끊어버리는 편리함을 제공
- cascade = CascadeType.PERSIST
- cascade = CascadeType.REMOVE
private static oid saveWithCascade(EntityManger em) {
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
child1.setParent(parent);
child2.setParent(parent);
parent.getChildren().add(child1);
parent.getChildren().add(child2);
em.persist(parent);
}
- 마지막 줄에 em.persist(parent); 이거 하나만으로 child1과 child2을 전부 영속화시켰다!
값 타입
- 이게 값타입을 이용한 엔티티
@Entity public class Member { @Id private Long id; private String name; @Embedded private Period workPeriod; @Embedded private Address homeAddress; } @Embeddable public class Period{ @Temporal(TemporalType.DATE) private Date startDate; @Temporal(TemporalType.DATE) private Date endDate; } @Embeddable public class Address{ private String city; private String street; private String zipcode; }
- 이러면 MEMBER테이블엔 7개의 컬럼이 들어온다.
- 추가적으로 값타입 클래스(Address)에는 equals와 hashCode 메소드가 오버라이딩 되어야한다
객체지향 쿼리 언어
- JPQL
- Criteria
- QueryDSL
-
네이티브 SQL
- JPQL은 필수적으로 알아야하는거고 Criteria나 QueryDSL은 결국 JPQL을 실수없이 효과적으로 쓰기위해 존재하는 도구와 같은 것
-
결국 JPQL을 완벽히 손에 익을만큼 연습하고 QueryDSL로 넘어가는게 좋아보임.
- JPQL
public interface MemberRepository extends JpaRepository<Member, Long> {
// 쿼리 메소드
List<Member> findByName(String name);
@Query("SELECT m FROM Member m JOIN m.team t WHERE t.name=:teamName")
List<Member> findMember(@Param(teamName) String teamName);
}
public interface BoardRepository extends JpaRepository<BoardEntity, Integer>{
@Query("SELECT file FROM BoardFileEntity file WHERE board_idx = :boardIdx AND idx = :idx")
BoardFileEntity findBoardFile(@Param("boardIdx") int boardIdx, @Param("idx") int idx);
}
댓글남기기