티스토리 뷰

생활코딩/JAVA

JPA 공부하자 - 01

우봉이 2019. 4. 18. 17:45

SQL 중심적인 개발의 문제점

  • 무한 반복, 지루한 코드
  • 테이블 마다 CRUD...
  • 자바 객체 <-> SQL 무한 루프
  • SQL 에 의존적인 개발을 피하기 어렵다.
  • 객채 지향 vs RDBMS 패러다임 불일치

Java Object vs Table

  • 연관관계
    • 객체는 참조를 사용 * 객체는 단방향
    • 테이블은 외래 키를 사용 * 테이블은 양방향

 

JPA는 Java Persistence API로 자바 ORM 표준을 의미한다.

JPA를 사용하면 애플리케이션 개발자는 엔티티 객체를 중심으로 개발하고 데이터베이스에 대한 처리는 JPA에 맡겨야 한다.

필요한 부분은 JPQL을 사용하여 쿼리를 만든다.

JPQL( Java Persitence Query Language )

JPQL 사용 시 테이블 명은 엔티티명으로 작성한다. ( JPQL 은 DB의 테이블 이름을 알지 못한다 )

 

엔티티 생명주기 ( Persistence Life Cycle )

  1. 비영속 - new / transient : 영속성 컨텍스트와 전혀 관계가 없는 상태
  2. 영속 - 영속성 컨텍스트에 저장된 상태
  3. 준영속 - 영속성 컨텍스트에 저장되었다가 분리된 상태 ( 트랜잭션에서 벗어난 상태 )
  4. 삭제 - 삭제된 상태

영속 상태에서는 반드시 식별자 값(ID)가 존재한다.

 

영속성 컨텍스트 장점

  1. 1차 캐시
    - 엔티티를 조회하면 1차 캐시에서 엔티티를 찾고 만약 찾는 엔티티가 없으면 DB에서 조회한다.
    - 1차 캐시에 엔티티가 존재하면, DB 조회를 하지 않고 바로 전달한다.
  2. 동일성 보장
  3. 트랜잭션을 지원하는 쓰기 지연
  4. 변경 감지
  5. 지연 로딩

 

동일성과 동등성

  • 동일성(identity) : 실제 인스턴스가 같다. A == B
  • 동등성(equality) : 실제 인스턴스는 다르지만 값이 같다. A.equals(B)

영속성 컨텍스트는 성능상 이점과 엔티티의 동일성을 보장한다.

 

트랜잭션 내에서는 커밋하기 직전까지 엔티티와 관련된 쿼리를 내부 쿼리 저장소에 저장하여, 커밋이 발생할 경우 DB에 쿼리를 전달한다. -> transactional write-behind

 

트랜잭션 내에서 강제로 커밋하는 방법은 flush() 이다.

 

변경 감지 

  • 트랜잭션 내에서 변경 감지가 발생할 경우(엔티티의 변경사항) 데이터베이스에 자동으로 반영한다.
  • 변경 감지는 영속 상태의 엔티티에만 적용된다.

영속성 컨텍스트를 플러시 하는 방법

  1. em.flush()를 직접 호출
  2. 트랜잭션 커밋
  3. JPQL 쿼리 실행(자동 호출)

준영속(detached) 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.

영속->준영속 으로 변경 시 1차 캐시에서 제거 된다.

 

준영속을 만드는 방법

  1. em.detach(entity) : 해당 엔티티만 준영속으로 전환
  2. em.clear() : 트랜잭션 내 1차 캐시가 모두 초기화(모두 준영속) - 트랜잭션이 종료된 것은 아님 / 쓰기 지연 저장소는 남아있음
  3. em.close() : 저장소 / 1차 캐시 모두 초기화

준영속 상태를 다시 영속 상태로 만드는 방법

  • em.merge() : 병합
  • 병합은 파라미터로 넘어온 엔티티의 식별자 값으로 영속성 컨텍스트를 조회하고, 찾는 엔티티가 없으면 데이터베이스에서 조회한다. 만약 데이터베이스에서도 발견하지 못하면, 새로운 엔티티를 생성해서 병합한다.
    병합은 준영속/비영속을 가리지 않으며, save or update 기능을 자체적으로 수행한다.
댓글