이 글은 “JPA 프로그래밍 입문 (최범균 저)” 책 내용을 정리한 글입니다.

만약 저작권 관련 문제가 있다면 “gunjuko92@gmail.com”로 메일을 보내주시면, 바로 삭제하도록 하겠습니다.

JPA 프로그래밍 입문 - JPA 시작하기

이 글은 “JPA 프로그래밍 입문 (최범균 저)” 책의 내용을 정리한 글입니다.

모델 클래스와 매핑 설정

  • @Entity는 해당 클래스가 JPA의 엔티티임을 의미한다.
    • 엔티티는 DB 테이블에 매핑되는 기본 단위이다.
    • @Table 애노테이션을 사용해서 어떤 테이블과 매핑되는지 설정한다.
  • JPA의 엔티티에는 식별자가 있다. @Id 애노테이션은 엔티티를 식별할 때 사용할 프로퍼티를 지정할 때 사용한다. 대부분 엔티티 클래스의 식별자는 DB 테이블의 주요키에 매핑한다.
  • java.util.Date 타입을 매핑할 때는 @Timestamp 애노테이션을 사용한다.
    • TemporalType.TIMESTAMP : java.sql.Timestamp로 값을 읽어온 뒤 자바 클래스로 변환
  • 쿼리를 생성할 때, 테이블에 읽어온 데이터로부터 자바 객체를 생성할 때 매핑정보를 이용한다.
    • 엔티티 클래스의 인자가 없는 기본 생성자를 이용해서 엔티티 객체를 생성
    • @Column 애노테이션 정보를 이용해서 칼럼 값을 필드에 할당 (@Column 애노테이션이 없는 경우는 칼럼명과 필드명을 비교해서 할당)
    • JPA는 테이블과 매핑된 클래스의 객체를 생성할 때 인자가 없는 기본 생성자를 사용한다. 따라서 엔티티 클래스는 반드시 기본생성자가 있어야만 한다.

JPA 설정

  • JPA는 기본적으로 클래스패스에 있는 META-INF/persistence.xml 파일을 설정 파일로 사용한다.
  • JPA는 영속 단위 별로 엔티티 클래스를 관리한다. 영속 단위는 <persistence-unit> 태그로 추가한다.
    • 한 개 이상의 영속 단위를 설정할 수 있으나 보통 하나의 애플리케이션은 하나의 영속단위를 가짐
    • 영속 단위는 JPA가 영속성을 관리할 단위이다. 영속 단위별로 매핑 대상, DB 연결 설정 등을 관리한다.
  • JPA는 로컬 트랜잭션과 JTA 기반 글로벌 트랜잭션을 지원한다. 로컬 트랜잭션은 자바 Connection을 이용해서 트랜잭션을 처리한다.
  • <class> 태그로 영속 단위에서 관리할 엔티티 클래스를 지정한다.
  • hibernate.dialect 속성은 하이버네이트가 쿼리를 생성할 때 사용할 Dialect 종류를 지정한다.
    • 이 값을 올바르게 지정해야 하이버네이트가 DB 종류에 맞는 쿼리를 생성한다.

영속 컨텍스트와 영속 객체 개요

  • @Entity 애노테이션을 붙인 클래스를 JPA에서는 엔티티 클래스라고 부르는데 이 엔티티는 DB에 보관되는 대상이 된다.
  • 엔티티를 영속 컨텍스트(persistence context)로 관리한다. 영속 컨텍스트는 JPA가 관리하는 엔티티 객체 집합이다.
  • 영속 컨텍스트에 속한 엔티티 객체를 DB에 반영한다.
  • 영속 컨텍스트에 보관된 객체를 영속 객체(persistent context)라고 부른다.
  • 영속 컨텍스트는 세션 단위로 생긴다. 즉 세션 생성 시점(EntityManager)에 영속 컨텍스트가 생성되고 세션 종료 시점에 컨텍스트가 사라진다.
  • JDBC 프로그래밍에서 DB 연동을 처리할 때 Connection을 사용하는 것처럼 JPA에서는 EntityManager를 사용해서 DB 연동을 처리한다.
  • EntityManager는 영속 컨텍스트와 엔티티를 관리한다.
  • 애플리케이션은 영속 컨텍스트에 직접 접근할 수 없다. 대신 EntityManager를 통해서 영속 컨텍스트와 관련된 작업을 수행한다.
    • EntityManager를 생성
    • 트랜잭션 시작 : JPA는 트랜잭션 범위에서 DB 변경을 처리하도록 제한하고 있기 때문에 트랜잭션을 먼저 시작해야 새로운 데이터를 추가하거나 기존 데이터를 변경할 수 있다. 수정 기능이 없고 조회만 하는 경우는 트랜잭션이 필요가 없다.
    • EntityManager를 통해 영속 컨텍스트에 객체를 추가하거나 조회
    • 트랜잭션 커밋
    • EntityManager를 닫는다.

일반적인 데이터베이스 프로그래밍과 절차가 유사하다. 대신 EntityManager와 JPA가 제공하는 트랜잭션을 사용하는 것이 다르다. JPA는 트랜잭션 범위에서 DB 변경을 처리하도록 제한하고 있기 때문에 먼저 트랜잭션을 시작해야 새로운 데이터를 추가하거나 기존 데이터를 변경할 수 있다.

  • EntityManagerFactory는 EntityManager를 생성하는 팩토리다. EntityManagerFactory는 영속 단위별로 생성한다. 애플리케이션 초기화 과정에서 한번만 생성하면 된다. 그리고 애플리케이션 종료 시점에 close() 메소드를 호출해서 팩토리를 종료한다. 이 시점에 커넥션 풀과 같은 자원을 반환한다.
  • JPA는 트랜잭션을 종료할 때 영속 컨텍스트에 존재하는 영속 객체의 값이 변경되었는지를 검사한다. 만약 값이 바뀌었다면 변경된 값을 DB에 반영하기 위해 update 쿼리를 실행한다. 이를 하이버네이트에서는 더티 체킹이라고 부른다.
  • JPA는 SQL과 유사한 JPQL을 제공한다. JPQL은 매핑 설정을 담은 클래스를 이용해서 쿼리를 작성한다.
    • EntityManger.createQuery() 메소드를 이용해서 쿼리 객체를 구한다.
    • 클래스의 매핑 정보를 사용해서 JPQL을 알맞은 SQL로 변환해서 실행하고 SQL 실행 결과로부터 필요한 객체를 생성한다.

정리

  • JPA를 사용하면 개발자가 직접 작성해야할 쿼리 수가 많이 줄어든다. 이는 개발자가 애플리케이션 로직을 구현하는데 집중할 수 있도록 해준다.
  • JPA가 쿼리를 직접 대신 생성하기 때문에 높은 성능이 요구되는 SQL 쿼리가 필요한 기능은 JPA의 쿼리 생성 기능이 오히려 문제를 유발할 수 있다.