자바 ORM 표준 JPA 프로그래밍 - 기본편 01

wisdom·2022년 8월 8일
0

김영한님의 자바 ORM 표준 JPA 프로그래밍 강의를 수강하면서 정리했습니다.

  • 처음 ~ 엔티티 매핑

SQL 중심 개발의 문제점

  • 패러다임의 불일치
    • 객체 VS 관계형 데이터베이스
  • 객체 -> SQL 변환 -> SQL -> RDB
  • 진정한 의미의 계층 분할이 어렵다.
  • 객체답게 모델링 할수록 매핑 작업만 늘어난다.
  • 객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수 없을까? 의 고민의 해결 방안이 JPA 다.

JPA

  • Java Persistence API
  • 자바 진영의 ORM 기술 표준
  • ORM
    • Object-relational mapping(객체 관계 매핑)
    • 객체는 객체대로 설계
    • 관계형 데이터베이스는 관계형 데이터베이스대로 설계
    • ORM 프레임워크가 중간에서 매핑
  • JPA는 애플리케이션과 JDBC 사이에서 동작

  • JPA는 인터페이스의 모음이다.
  • JPA 2.1 표준 명세를 구현한 3가지 구현체
    • 하이버네이트, EclipseLink, DataNucleus

JPA 동작 순서

유저 회원가입 상황이라면?

  • JPA 에게 유저 정보를 넘긴다.
  • JPA가 해당 엔티티를 분석하고,
  • JPA가 INSERT SQL 생성하고,
  • JPA가 JDBC API 사용해서 DB에 넘긴다.

    패러다임의 불일치를 해결해준다.

JPA를 왜 사용해야 할까?

  • SQL 중심적인 개발에서 객체 중심으로 개발
  • 생산성
  • 유지보수
  • 패러다임 불일치 해결
  • 성능
  • 데이터 접근 추상화와 벤더 독립성
  • 표준

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

JPA 구동 방식

  1. JPA에는 Persistence 라는 클래스가 있다. 여기가 시작점이다.
  2. 그리고 설정 정보를 META-INF/persistence.xml 에서 읽어서 EntityManagerFacotry 라는 클래스를 생성한다.
  3. 필요할 때마다 EntityManagerFacotry 에서 EntityManager 를 찍어낸다.

주의

  • 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
  • 엔티티 매니저는 쓰레드 간에 공유X
    • 사용하고 버려야한다.
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행

영속성 컨텍스트

JPA에서 가장 중요한 2가지
- 객체와 관계형 데이터베이스 매핑하기
- 영속성 컨텍스트

  • "엔티티를 영구 저장하는 환경" 이라는 뜻
  • EntityManager.persist(entity)
  • 영속성 컨텍스트는 논리적인 개념
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근

엔티티의 생명주기

  • 비영속(new/transient)
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  • 영속(managed)
    • 영속성 컨텍스트에 관리되는 상태
  • 준영속(detached)
    • 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제(removed)
    • 삭제된 상태

영속성 컨텍스트의 이점

  • 1차 캐시
  • 영속 엔티티의 동일성 보장
  • 엔티티를 등록할 때 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지(Dirty Checking)

플러시

  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것

플러시가 발생하면?

  • 변경 감지
  • 수정된 엔티티를 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송
    • 등록, 수정, 삭제 쿼리

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

  • em.flush()
    • 직접 호출
  • 트랜젝션 커밋
    • 플러시 자동 호출
  • JPQL 쿼리 실행
    • 플러시 자동 호출

플러시 정리

  • 영속성 컨텍스트를 비우지 않음
  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화
  • 트랜젝션이라는 작업 단위가 중요
    • 커밋 직전에만 동기화하면 됨

준영속 상태

  • 영속 -> 준영속
  • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리
  • 영속성 컨텍스트가 제공하는 기능을 사용 못함

객체와 테이블 매핑

@Entity

  • @Entity 가 붙은 클래스는 JPA가 관리
  • JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수
  • 기본 생성자 필수
    • 파라미터가 없는 public 또는 protected 생성자
  • final 클래스, enum, interface, inner 클래스 사용 X
  • 저장할 필드에 final 사용 X

기본 키 매핑

  • 직접 할당
    • @Id 만 사용
  • 자동 생성
    • @GeneratedValue 만 사용
    • IDENTITY
      • 기본키 생성을 데이터베이스에 위임
      • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
        • ex) MySQL의 AUTO_INCREMENT
      • JPA 는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행
      • AUTO_INCREMENT 는 데이터베이스에 INSERT SQL을 실행한 이후에 ID값을 알 수 있음
        • 즉 디비에 값이 들어가야 ID값을 알 수 있다는 문제가 있다. 그게 무슨 문제냐면 영속성 컨텍스트에서 관리되려면 PK값이 있어야 하는데 DB에 넣기 전까지 영속성 컨텍스트의 1차캐시 부분에서 @Id 값을 알 수가 없다는 문제가 있다.
        • 위 문제를 해결하기 위해 IDENTITY 전략만 em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회함.
    • SEQUENCE
      • 데이터베이스 시퀀스 오브젝트 사용
      • ORACLE @SequenceGenerator 필요
    • TABLE
      • 키 생성용 테이블 사용
      • 모든 DB에서 사용
      • 단점으로 성능 이슈가 있다.
      • @TableGenerator 필요
    • AUTO
      • 방언에 따라 자동 지정
      • 기본값

권장하는 식별자 전략

  • 기본 키 제약 조건
    • null 아님
    • 유일
    • 변하면 안된다.
      • 미래까지 변하지 않는 조건을 만족하는 자연키를 찾기 어려움(-> 그래서 대리키를 사용하자)
  • 권장: Long 타입 + 대체키 + 키 생성전략 사용
    • 10억이 넘어도 정상적으로 동작해야하기 때문에 Long 타입 사용

데이터 중심 설계의 문제점

@Entity
public class Order {
    @Column(name = "ORDER_ID")
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

   ** @Column(name = "MEMBER_ID")
    private Long memberId;**
  • 객체 설계를 테이블 설계에 맞춘 방식
  • 테이블의 외래키를 객체에 그대로 가져옴
  • 객체 그래프 탐색이 불가능
  • 참조가 없으므로 UML도 잘못됨
profile
문제를 정의하고, 문제를 해결하는

0개의 댓글