Skip to content

Latest commit

 

History

History
183 lines (145 loc) · 5.7 KB

1.Quickly_Intro.md

File metadata and controls

183 lines (145 loc) · 5.7 KB

JPA

  • EntityManagerFactory는 하나만 생성하여 애플리케이션 전체에서 공유해야 한다.
  • EntityManager는 Thread 간에 공유하면 안된다. (사용하고 버려야 한다.)
  • JPA의 모든 데이터 변경은 Transaction 안에서 실행한다.

DB 스키마 자동 생성

hibernate.hbm2ddl.auto

  • create: 기존 테이블 삭제 후 재생성 (DROP + CREATE)
  • create-drop: create와 같으나 종료 시점에 테이블 DROP
  • update: 변경분만 반영
  • validate: Entity와 테이블이 정상 맵핑되었는지 확인
  • none: 사용하지 않음

주의

  • 개발 : create, update
  • 테스트 : update, validate
  • 스테이징과 운영 : validate, none

연관 관계의 주인과 mappedBy

객체의 양방향 연관 관계

  • 객체의 양방향 연관 관계는 사실 양방향 연관 관계가 아니라 서로 다른 단방향 연관 관계 2개다.

객체를 양방향으로 참조하려면 단방향 연관 관계를 2개 만들어야 한다.

테이블의 양방향 연관 관계

  • 테이블은 FK 하나로 두 테이블의 연관 관계를 관리한다.
  • MEMBER.TEAM_ID(FK) 하나로 양방향 연관 관계를 가진다. (양쪽으로 JOIN 할 수 있다.)
SELECT *
FROM MEMBER M 
JOIN TEAM T ON M.TEAM_ID = T.ID

SELECT *
FROM TEAM T 
JOIN MEMBER M ON T.ID = M.TEAM_ID

연관 관계의 주인 (Owner)

양방향 맵핑 규칙

  • 객체의 두 관계 중 하나를 연관 관계의 주인으로 지정한다.
  • 연관 관계의 주인만이 FK를 관리한다. (등록, 수정)
  • 주인이 아닌 쪽은 Read만 가능하다.
  • 주인은 mappedBy 속성 사용 X, 주인이 아니면 mappedBy 속성으로 주인 지정한다.

누구를 주인으로?

  • FK가 있는 곳을 주인으로 한다.

양방향 맵핑 언제?

  • 단방향 맵핑만으로도 이미 연관 관계 맵핑은 된 것이고, 양방향 맵핑은 반대 방향 조회(객체 그래프 탐색) 기능이 추가된 것뿐이다.
  • JPQL에서 역방향으로 탐색할 일이 많다.
  • 단방향 맵핑을 잘하고 양방향 맵핑은 필요할 때 추가해도 된다. (테이블에 영향이 없다.)

JPA 내부 구조

영속성 컨텍스트 (PersistenceContext)

  • JPA를 이해하는데 가장 중요한 용어
  • Entity를 영구 저장하는 환경이라는 뜻
  • EntityManager.persist(entity);
  • 영속성 컨텍스트는 논리적 개념 (눈에 보이지 않는다.)
  • EntityManager를 통해 영속성 컨텍스트에 접근한다.

Entity LifeCycle

비영속(new/transient): 영속성 컨텍스트와 전혀 관계가 없는 상태

Member member = new Member();
member.setId(1L);
member.setName("회원1");

영속(managed): 영속성 컨텍스트에 저장된 상태

Member member = new Member();
member.setId(1L);
member.setName("회원1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

em.persist(member);

준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태

em.detach(member);  // 특정 엔티티만 준영속 상태로 전환
또는
em.clear(); // 영속성 컨텍스트 초기화
또는
em.close(); // 영속성 컨텍스트 종료

삭제(removed): 삭제된 상태

em.remove(member);

영속성 컨텍스트의 이점

1차 캐시 & 동일성(identity) 보장
반복 가능한 읽기(REPEATABLE READ) 등급의 트랙잭션 격리 수준을 DB가 아닌 애플리케이션단에서 제공

Member a = em.find(Member.class, 1L);
Member b = em.find(Member.class, 2L);
System.out.println(a == b); // true

트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();

em.persist(a);
em.persist(b);
// 여기까지는 INSERT 쿼리를 DB에 보내지 않는다.

transaction.commit();   // 커밋하는 순간 DB에 쿼리를 보낸다.

변경 감지 (Dirty Checking)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();

Member a = em.find(Member.class, 1L);
a.setName("Hardy");
a.setAge(30);

// em.update(a); 이런 코드가 없어도 된다.

transaction.commit();
// 1차 캐시를 만들 때 만들어둔 스냅샷과 비교하여 변경된 부분의 UPDATE 쿼리를 수행한다.

지연 로딩 (Lazy Loading)


프록시와 지연 로딩

  • 가급적 지연 로딩을 사용하자.
  • 즉시 로딩을 적용하면 예상하지 못한 쿼리가 발생할 수 있다.
  • 즉시 로딩은 JPQL에서 N+1 문제를 발생시킨다.
  • @ManyToOne, @OneToOne은 default가 즉시 로딩이다.
  • @OneToMany, @ManyToMany는 default가 지연 로딩이다.

JPA와 객체지향쿼리

JPQL

  • SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어
  • SQL과 유사한 문법의 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 등 지원
  • JPQL은 Entity 객체를 대상으로 쿼리 (SQL은 DB 테이블을 대상으로 쿼리)
String jpql = "select m from Member m where m.age > 18";
List<Member> result = em.createQuery(jpql, Member.class).getResultList();

페이징 쿼리

String jpql = "select m from Member m order by m.name desc";
List<Member> result = em.createQuery(jpql, Member.class)
        .setFirstResult(10)
        .setMaxResults(20)
        .getResultList();

FETCH JOIN

  • Entity 객체 그래프를 한번에 조회하는 방법
  • 별칭을 사용할 수 없다.
JPQL: select m from Member m join fetch m.team
SQL: select M.*, T.* from MEMBER T inner join TEAM T on M.TEAM_ID = T.ID

예제 코드

https://github.com/Spring-Data-Things/JPA-Intro