JPA
영속성 관리
- EntityManager Factory(1)-> EntityManager(N) 생성-> PersistenceContext(1) 커넥션풀-> db
- 엔티티 생명주기: 비영속(new),영속(persist,merge),준영속(detach,clear,close),삭제(remove)
- 이점:1차 캐시,동일성(같은 트랜잭션 안),쓰기 지연,변경 감지(엔티티와 스냅샷 비교),지연 로딩
- 플러시: 직접flush,트랜잭션 커밋,JPQL 쿼리 실행, 옵션 setFlushMode(FlushModeType.COMMIT/AUTO)
엔티티 매핑
- 객체와 테이블 매핑:
- @Entity(기본 생성자 필수),
- @Table(name,catalog,schema,uniqueConstraints)
필드와 컬럼 매핑:
- @Column((name = "name", nullable = false, length = 10)
- @Enumerated(EnumType.STRING): enum
- @Lob:CLOB(문자),BLOB(나머지)
- @Transient: db x
기본 키 매핑:
- @Id @GeneratedValue :Long형 + 대체키 + 키 생성전략
- (strategy = GenerationType.IDENTITY/SEQUENCE/TABLE)
연관관계 매핑
단방향
Member @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; member.setTeam(team);
양방향 연관관계 주인
Team에 추가 @OneToMany(mappedBy = "team")//주인x , 읽기만 List<Member> members = new ArrayList<Member>(); findTeam.getMembers().size();
- 객체와 테이블 차이
- 객체: 멤버에 팀, 팀에 멤버스->사실상 단방향 2개
- 테이블: 멤버에 팀id fk->외래키로 조인o
- 연관관계 주인: 외래키 관리, 등록수정
- 주인x: 읽기만, mappedBy
- 주의: 양방향 매핑시 항상 양쪽다 값을 입력(연관관계 편의 메소드), 무한 루프 조심
다양한 연관관계 매핑
- 다대일 단방향: 다(N) 연관관계의 주인
- 일대다 단방향: 일(1)이 연관관계의 주인<->테이블:다(N) 쪽에 외래 키
고급 매핑
상속관계 매핑: @Inheritance(strategy=InheritanceType.XXX)
• 각각 테이블로 변환 -> 조인 전략 JOINED
• 통합 테이블로 변환 -> 단일 테이블 전략 SINGLE_TABLE- @DiscriminatorColumn(name=“DTYPE”) - @DiscriminatorValue(“XXX”)
• 서브타입 테이블로 변환 -> 구현 클래스마다 테이블 전략 TABLE_PER_CLASS
@MappedSuperclass: 공통 매핑 정보(ex.id,name)
프록시와 연관관계 관리
- 프록시: em.getReference() 가짜 엔티티 객체 조회, 실제 클래스>프록시
- 프록시 초기화 -> 프록시 통해 실제 엔티티 접근
- 즉시 로딩과 지연 로딩:
- 지연 로딩: @ManyToOne(fetch = FetchType.LAZY) 프록시로 조회 -> 사용 시점에 초기화 member.getTeam().getName();
- 즉시 로딩: JPQL에서 N+1 문제, 사용x->fetch 조인, 엔티티 그래프
- 영속성 전이: CASCADE, 연관 엔티티 함께(부모->자식)
- @OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
- 고아 객체 제거: 연관관계 끊어진 자식 삭제 orphanRemoval = true(CascadeType.REMOVE)
- 부모 엔티티 통해 자식 생명주기 관리
값 타입
- 엔티티 타입: @Entity, 식별자로 추적 가능
- 값 타입: 단순 값-자바 기본 타입/객체, 식별자x 추적 불가, equals 비교
- 임베디드 타입: @Embeddable(정의),@Embedded(사용),기본 생성자,엔티티에 생명주기 의존, 공유 위험->복사해서 사용, 불변 객체로 설계(생성자)
- 값 타입 컬렉션: 값 타입 하나 이상, 별도의 테이블, 변경 사항->다 삭제하고 다시 저장-> 대안: 일대다 관계
객체지향 쿼리 언어(JPQL)
소개
- JPQL은 엔티티 객체를 대상으로 쿼리
String jpql = "select m From Member m where m.name like ‘%hello%'"; List<Member> result = em.createQuery(jpql, Member.class) .getResultList();
- QueryDSL: 자바코드
JPAFactoryQuery query = new JPAQueryFactory(em); QMember m = QMember.member; List<Member> list = query.selectFrom(m) .where(m.age.gt(18)) .orderBy(m.name.desc()) .fetch();
- 네이티브 SQL
em.createNativeQuery(sql, Member.class).getResultList();
JPQL - 기본 문법과 기능
- TypeQuery: 반환 타입 명확 <-> Query: 명확 x
- getResultList():결과 하나 이상(List) <-> getSingleResult():결과 정확히 하나(단일 객체,결과하나x->예외)
- 파라미터 바인딩: :username<-setParameter("username", usernameParam);
- DTO로 바로 조회: SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM
Member m - 페이징
em.createQuery(jpql, Member.class) .setFirstResult(10)//조회 시작 위치 .setMaxResults(20)//조회할 데이터 수 .getResultList();
- 조인
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
JPQL - 경로 표현식
.(점) 찍어 객체 그래프 탐색
상태 필드: m.username
단일 값 연관 필드: m.team, 묵시적 내부 조인, 탐색o
컬렉션 값 연관 필드: m.orders, 묵시적 내부 조인, 탐색x
**명시** select m from Member m join m.team t 묵시 select m.team from Member m 컬렉션 값 연관 필드: 명시적 조인 통해 별칭 select t.members.username from Team t(x) select m.username from Team t join t.members m(o)
JPQL - 페치 조인
성능 최적화, 연관된 엔티티 함께 조회
페치 조인 select m from Member m join fetch m.team DISTINCT: 애플리케이션에서 엔티티 중복 제거 컬렉션 페치 조인: 페이징x select distinct t from Team t join fetch t.members where t.name = ‘팀A’
JPQL - 다형성 쿼리
select i from Item i where type(i) IN (Book, Movie)
select i from Item i where treat(i as Book).auther = ‘kim’
JPQL - 엔티티 직접 사용
- 엔티티 직접 사용 = 기본 키 값
m = :member m.id = :memberId
JPQL - Named 쿼리
- JPQL 쿼리에 이름 부여,
- 애플리케이션 로딩 시점에 초기화
@NamedQuery( name = "Member.findByUsername", query="select m from Member m where m.username = :username")
JPQL - 벌크 연산
- 쿼리 한 번으로 여러 테이블 로우 변경 executeUpdate(), 영속성 컨텍스트 초기화