2019년 2월 11일 월요일

JPA 기술 노트

2018.11.22 T아카데미 JPA 기술세미나 참석시 기록.

JPA는 Spring Data로 실제 담당 시스템에 적용되어 사용하고 있기는 하나 기본 개념의 재정립이 절실하던 중 T아카데미에서 관련 세미나 소식이 들려왔다.

강의하시는 분이 자바 ORM 표준 JPA 프로그래밍 저자이기도 해서 바로 신청했는데 짧은 시간 내에 굉장히 유익했던 내용이었다.

실습 준비

H2 데이터베이스 설치 (http://www.h2database.com)

JPA와 모던 자바 데이터 저장 기술
객체와 관계형 데이터베이스의 차이

  1. 상속 객체 [상속 관계 - Table 수퍼타입 서브타입 관계]
  2. 연관관계
    • 객체는 참조를 사용: member.getTeam()
    • 테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID
  3. 데이터 타입

ORM?

  • Object-relational mapping(객제 관계 매핑)
  • 객체는 객체대로 설계
  • 관계형 데이터베이스는 관계형 데이터베이스 대로 설계
  • ORM 프레임워크가 중간에서 매핑

JPA는 표준 명세

  • JPA는 인터페이스이고 실제로 구현된 것은 하이버네이트이다.
  • SQL 중심적인 개발에서 객체 중심으로 개발

JPA의 성능 최적화 기능

  1. 1차 캐시와 동일성 보장
    • 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상
  2. 트랜잭션을 지원하는 쓰기 지연
    • 트랜잭션을 커밋할 때까지 INSERT SQL을 모음
    • JDBC BATCH SQL를 사용해서 한꺼번에 DB에 전송하고 커밋
  3. 지연 로딩(Lazy Loading)
    • 지연 로딩 - 객체가 실제 사용될 때 로딩
    • 즉시 로딩 - JOIN SQL로 한번에 연관된 객체까지 미리 조회

ORM은 객체와 RDB 두 기둥 위에 있는 기술

실습

1. H2 DB에서 테스트 테이블 생성

2. Maven 프로젝트 생성하여 jpa, h2database 라이브러리 추가

3. Main클래스와 Entity클래스를 생성

4. persistence.xml 파일을 생성하여 /resources/META-INF/ 디렉터리에 넣음

5. Main클래스에 데이터 등록 코드 작성

6. H2 DB에 실제 데이터가 등록되었는지 확인해본다.

  • 엔터티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
  • 엔터티 매니저는 쓰레드 간에 공유하면 안된다. (사용하고 버려야 됨)

데이터베이스 스키마 자동 생성하기

  • DDL을 애플리케이션 실행 시점에 자동 생성
  • 테이블 중심 -> 객체 중심
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL생성
  • 이렇게 생성된 DDL은 개발 장비에서만 사용

hibernate.hbm2ddl.auto

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

식별자 매핑 방법 @Id (직접 매핑)

  • IDENTITY : 데이터베이스에 위임, MYSQL
  • SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용

권장하는 식별자 전략

  • 기본키 제약 조건 : not null, 유일, 변하면 안된다.
  • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
  • 예를 들어 주민등록번호도 기본 키로 적절하지 않다.
  • 권장 : Long + 대체키 + 키 생성전략 사용 

연관관계의 주인과 mappedBy

  • 객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개다.
    • 객체의 두 관계 중 하나를 주인으로 설정하고 주인 객체에서 일어나는 업데이트 동작만 실제 DB에 적용
    • ‘mappedBy’ 는 주인이 아니고 조회만 되는 것
    • 주인은 mappedBy 속성 사용하지 않음
    • 주인이 아니면 mappedBy 속성으로 주인을 지정
    • 외래 키가 있는 곳을 주인으로 정해라
      • 어지간하면 단방향으로 설계를 끝내라
      • 필요하면 반대쪽 객체에 mappedBy 설정만 추가해라

주인이 아닌 객체에 member객체를 추가하고 저장

외래키가 null로 들어감

주인인 객체에 team객체를 셋팅 후 저장

외래키가 저장됨

  • 테이블은 외래 키 하나로 두 테이블의 연관관계를 정리

JPA 내부 구조

  • 영속성 컨텍스트
    • 객체를 생성한 상태(비영속 - new)
    • 객체를 저장한 상태(영속 - managed)

트랜잭션을 커밋하거나 JPQL를 사용할 때 플러시가 자동으로 되나 Spring Data등 다른 라이브러리랑 섞어 쓸 때는 수동으로 .flush()메서드로 수행한다.

연관관계와 함께 지연로딩을 설정했을 때, 엔터티 매니저를 클로징한 뒤(em.close();) 조회를 시도하면 에러가 발생한다.

JPA와 객체지향 쿼리

  • JPQL
  • 외부에 제공하는 API는 엔터티가 아닌 별도의 dto를 만들어서 제공하는 것을 권장 (엔터티 변경 시마다 API도 변경되버려 운영에 어려움)

JPA 기반 프로젝트

  • Spring Data JPA
  • QueryDSL - 문자가 아닌 코드로 작성

댓글 없음:

댓글 쓰기

Kotlin, SpringBoot 3, GraalVM 환경에서 Native Image로 컴파일하여 애플리케이션 실행

Spring Boot 3부터, GraalVM Native Image를 공식 지원하여 애플리케이션의 시작 속도와 메모리 사용량을 크게 줄일 수 있다. Native Image란 기존의 JVM 기반 위에서 돌아가는 Java 애플리케이션과는 달리 JVM 없이...