JPA스터디 - 1

한상우·2022년 11월 13일
0

JPA

목록 보기
1/7

시작하기전

JPA를 혼자 공부하는 것보다 다른 사람들과 같이 공부하면서 설명하는게 더 효과적이라 생각하여 진행한다.
JPA 스터디는 3명의 인원과 오프라인으로 매주 토요일 오전 10시에 진행한다

책은 자바 ORM 표준 JPA 프로그래밍 (저자: 김영한) 으로 진행하고 목표는 완독이다.

11/5

장소: 강남역 곤트란쉐리에
시간: 10:00 ~ 12:00


1장

개발시 CRUD용 SQL의 반복이 너무 많음

ORM프레임워크

  • 객체와 관계형 DB 간의 차이를 중간에서 해결해줌
  • JPA는 자바 진영의 ORM 기술 표준

JPA

  • CRUD SQL을 알아서 처리
  • 객체 모델링과 관계형 DB 사이의 차이점 해결
  • 애플리케이션을 SQL이 아닌 객체 중심으로 개발
    • 테스트 용이
    • 생산성과 유지보수 좋아짐

SQL을 직접 다룰 떄 문제점

  • 용어 정리
JDBC: 여러 관계형 DB에 접속하여 자바와 DB 사이에 데이터를 주고받을 수 있도록 지원하는 표준 자바 응용 프로그래밍 인터페이스
JDBC API: SQL을 이용해 자바로 DB 응용 프로그래밍을 작성할 수 있도록 지원

JDBC API가 인터페이스만을 제공해주면 실질적인 구현은 DBMS 제조사들이 자신들의 DB에 맞게 구현하여 제공 -> 이를 JDBC 드라이버라고 함
즉, JDBC API를 사용하면 하나의 자바 응용 프로그램만으로 JDBC 드라이버를 제공하는 어떤 관계형 DBMS에도 접근이 가능한 것.

1. 반복적인 작업

회원을 조회하는 기능을 개발한다 했을 때

  1. 회원 조회용 SQL을 작성

    SELECT ID, NAME, AGE FROM MEMBER WHERE ID = ?

  2. JDBC API를 사용해 SQL을 실행

    executeQuery(sql)

  3. 조회 결과를 Member 객체로 매핑

    String name = findMember.getString("NAME");
    int age = findMember.getString("AGE");
    Member member = new Member();
    member.setName(name);
    member.setAge(age);

1 ~ 3 과정을 기능을 추가할 때마다 계속 반복해야 한다

DB는 객체 구조와 다르기에 객체를 직접 DB에 저장하거나 조회할 수 없다
따라서 개발자가 중간에서 SQL과 JDBC API를 사용해 변환 작업을 해주어야 한다

  • 너무 많은 반복 작업이 일어난다.

2. SQL에 의존적인 개발

  • 데이터 접근 계층을 사용해서 SQL을 숨겨도, DAO를 열어서 어떤 SQL이 실행되는지 확인해야 함
  • 이처럼 SQL에 모든 것을 의존하게 되면, 엔티티를 신뢰할 수 없다.
  • SQL과 JDBC API를 데이터 접근 계층에서 숨겨도, 논리적으로 엔티티(비지니스 요구사항을 모델링한 객체)와 아주 강한 의존관계를 가지고 있다

JPA와 문제 해결

  • 개발자가 직접 SQL을 작성하는 것이 아닌, JPA가 제공하는 API를 사용하면 된다


객체와 관계형DB 패러다임 차이

  • 객체와 관계형 DB는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법도 다르다
  • 객체 구조를 테이블 구조에 저장하는 데는 한계가 있다
  • 불일치 문제는 개발자가 중간에서 해결해야 한다

상속

  • 객체는 상속이라는 개념이 있지만, 테이블은 상속이라는 개념이 없다
  • 개발자는 자바 컬렉션에 객체를 저장하듯이 JPA에게 객체를 저장하면 된다
  • jpa.persist(상속관계 있는 객체) 를 하게 되면 JPA가 상속에 맞게 조회 및 저장을 하게 된다

연관관계

  • 객체는 참조를 사용해서 연관된 객체를 조회하고

  • 테이블은 외래키를 사용해서 연관된 테이블을 조회한다

  • 객체를 테이블에 맞게 모델링을 하게 되면 객체지향의 특징을 잃어버리게 된다

  • 객체는 참조를 통해서 관계를 맺음

  • 이때 개발자가 중간에서 변환 역할을 할 때 패러다임 불일치에 따라 해결을 위한 비용이 발생

  • JPA를 사용하면 이를 해결

    member.setTeam(team) 회원과 팀 참조 관계
    jpa.persist(member) 회원과 연관관계 함께 저장

객체 그래프 탐색

  • 객체에서 참조를 사용해 연관된 관계를 찾는 것을 객체 그래프 탐색이라고 한다

  • 객체는 마음껏 객체 그래프를 탐색할 수 있다.
    member.getOrder().getOrderItem()

  • 반면 SQL을 직접 다루게 되면 할 수 없다. 처음 실행하는 SQL에 따라 탐색 범위가 정해지는데, 언제 객체 그래프가 끊어질지 모르기에 함부로 탐색할 수 없다.

  • JPA는 연관된 객체를 사용하는 시점에 적절한 SELECT SQL을 실행
    -> 실제 객체를 사용하는 시점까지 DB조회를 미룬다고 해서 지연로딩 이라고 한다

비교

  • JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장한다
  • 자바 코드에서 getMember 로 member 객체를 호출 여러번 한다면 각각 다른 인스턴스가 된다 (new Member())

결국 JPA는 패러다임 불일치 문제를 해결해주고, 정교한 객체 모델링을 유지하게 도와준다


JPA란??

  • 용어정리

    ORM: 객체와 관계형 DB를 매핑
    ORM프레임워크를 사용하면, 단순히 SQL을 개발자 대신 생성해 DB에 전달 할 뿐만 아니라
    패러다임 불일치 문제들도 해결
    매핑 방법은 ORM 프레임워크에서 알려준다
    자바 진영에서는 하이버네이트 프레임워크가 성숙한 ORM 프레임워크다
  • 하이버네이트를 기반으로 자바 ORM 표준이 만들어진게 JPA다

  • JPA는 자바 ORM 기술에 대한 API 표준 명세다 (인터페이스를 모아둔것)

  • JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다

JPA 장점

  1. 생산성
  • jpa.persist(member) 처럼 JPA에게 객체를 전달만 하면 된다, 반복적인 일은 JPA가 해준다
  • DDL 문을 자동으로 생성해주는 기능이 있어, DB 설계 중심 패러다임에서 객체 설계 중심으로 역전 시킬 수 있다
  1. 유지보수
  2. 패러다임 불일치 해결
  3. 성능
  • jpa.find(memberId) 를 여러번 해도 처음만 DB에 쿼리를 전달하고, 이후부터는 조회한 회원 객체를 재사용한다
  1. 데이터 접근 추상화
  • 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 한다
  1. 표준

스터디를 통해 알게 된 내용

  • maven과 gradle의 차이

    • 장점이라고 생각하는 부분은 가독성 부분과 성능에서 gradle이 maven을 이기고 있다
  • jpa가 성능적으로 좋지 않은 이유?

    • 아무래도, jpa는 날 쿼리가 아닌 jdbc를 한 번 감싼 형태이기에 느리지 않을까??

2장

엔티티 매니저 설정 (maven)

책에서는 maven 을 기준으로 설명을 진행
JPA는 META-INF/persistence.xml을 사용해서 필요한 설정 정보를 관리

<persistence-unit name="jpabook">
// 앤티티 매니저 팩토리 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");

// 앤티티 매니저 생성
EntityManager em = emf.createEntityManager();

// 트랜잭션 획득
EntityTransaction tx = em.getTransaction();

// 트랜잭션 시작
tx.begin();

// 트랜잭션 커밋
tx.commit();

// 앤티티 매니저 종료
em.close();

// 앤티티 매니저 팩토리 종료
emf.close();

Persistence 클래스가 META-INF/persistence.xml 설정 정보를 조회하여 앤티티 매니저 팩토리를 생성
앤티티 매니저 팩토리는 비용이 아주 크기 때문에, 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 함
앤티티 매니저 팩토리에서 앤티티 매니저를 생성함
앤티티 매니저를 통해 앤티티를 데이터베이스에 CRUD 할 수 있음


방언

  • 각 DB마다 제공하는 SQL 문법과 함수가 조금씩 다르다 (DB만의 고유한 기능을 JPA에서는 방언이라 함)
  • JPA 구현체들은 (하이버네이트) DB 방언 클래스를 제공함

JPQL

  • JPA를 사용하면 개발자는 객체를 중심으로 개발하므로, 검색도 객체를 대상으로 검색을 하게 되는데
  • 객체를 대상으로 검색하려면, DB의 모든 데이터를 애플리케이션으로 불러와서 앤티티 객체로 변경한 다음 검색해야 한다. (불가능)
  • 필요한 데이터만 불러오려면 결국 검색 조건이 포함된 SQL을 사용해야 하는데, JPQL이라는 쿼리 언어가 이를 해결해준다.

JPQL은 앤티티 객체를 대상으로 쿼리함

  • select m from Member m

SQL은 테이블을 대상으로 쿼리함

  • select M.ID, M.NAME, M.AGE from MEMBER M

  • 자세한건 10장에서..


앤티티 매니저 설정 (스프링부트)

  • 스프링 프레임워크 내 JPA를 사용할 때는 트랜잭션을 관리하는 일을 프레임워크가 처리함, 애플리케이션 초기화 시점에 EntityManager를 Bean으로 등록하고
@PersistenceUnit
private EntityManagerFactory factory;


@PersistenceContext
private EntityManager em;
  • PersistenceContext 어노테이션을 통해 EntityManager를 빈으로 등록할 수 있음
    이때 EntityManagerFactory에서 생성된 em을 생성하거나 기존의 em을 반환해준다

  • EntityManager는 여러 스레드가 동시에 접속하면 동시성 문제가 발생하여 공유해서는 안됨
    PersistenceContext로 엔티티 매니저를 주입받아도 괜찮은 이유는

  • 스프링 컨테이너가 초기화 되면서 EntityManager를 Proxy로 감싸는데
    그리고 Proxy를 통해 EntityManager를 생성하여 thread-safe를 보장함 (이 부분은 아직 이해가 잘 안된다.. 왜 Proxy로 감싸면 스레드 safe를 보장하지??)
    : 프록시.. 책 뒤편에 나온다고 한다!

profile
안녕하세요 ^^

0개의 댓글