LostCatBox

(JPA) JPA 기본편 CH01 (JPA 시작)

Word count: 788Reading time: 4 min
2023/04/05 20 Share

왜?

sql, jpql, mybatis 등등을 활용할때는 개발자가 결국 직접 sql을 쓰는것과같다.

하지만 JPA는 객체지향으로 쿼리를 만들고 개발할수있다.

출처

김영한 JPA 기본편

목표

객체와 테이블 설계 매핑

  • 기본 키와 외래키
  • 1:N, N:1, 1:1, N:M 매핑
  • 실무 노하우 + 성능까지 고려
  • 복잡한 시스템도 JPA로 설계 가능

JPA 내부 동작 방식 이해

  • JPA의 내부 동작 방식을 이해하지 못함
  • JPA가 어떤 SQL을 만들어 내는지 이해
  • JPA가 언제 SQL을 실행하는지 이해

JPA 기본

SQL 단점

  • 객체에 필드 추가시 insert update delete 문에 모두 다 추가해야한다.
  • 객체 지향 프로그래밍의 추상화, 캡슐과, 다형성, 상속등과 지향점이 틀리다

스크린샷 2023-04-05 오후 10.55.34

객체(JAVA)와 관계형 데이터 데이터베이스의 차이(지향점차이)

  1. 상속
    관계형 DB에서는 상속에서 추가, 조회할려면 각각 모든 해당 DB 모두 join해야한다.

  2. 연관관계
    member.getTeam() VS JOIN ON M.TEAM_ID = T.TEAM_ID
    객체는 team_id가 아닌 team객체의 주소를 가짐

    또한 RDB에서는 SQL문에서 이미 가져올수있는 값이 정해진다.
    member.getTeam() 는 되지만, member.getOrder().getDelivery()는 안될수있음(신뢰성문제)

  3. 데이터 타입

  4. 데이터 식별 방법
    ==를 할경우? SQL은 결국 마지막에 new 객체이므로 참조값 다를수밖에없다

객체를 자바 컬렉션에 저장 하듯, DB에 저장가능할까? -> JPA

신뢰할수있는 엔티티, 계층을 가진다!
(객체가있다면 어떤 필드를 get()해도 null은 일어나지않음)

JPA 란?

ORM이란?

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

스크린샷 2023-04-05 오후 11.15.37

  • Save()

스크린샷 2023-04-05 오후 11.16.25

  • Find()

스크린샷 2023-04-05 오후 11.16.38

JPA를 사용해야하는이유

  • SQL 중심적인 개발에서 객체 중심으로 개발
  • 생산성
  • 유지보수
  • 패러다임의 불일치 해결
  • 성능
  • 데이터 접근 추상화와 벤더 독립성
  • 표준
1
2
3
4
jpa.persist(member) //저장
Member member = jpa.find(memberId) //조회
member.setName(“변경할 이름”) //수정
jpa.remove(member) //삭제

JPA의 성능 최적화 기능

  1. 1차 캐시와 동일성(identity) 보장 => 캐시
  2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind) => 모아서보냄
  3. 지연 로딩(Lazy Loading) => 미루다가, 객체의 데이터가 필요한 시점에 쿼리, 즉시로딩을 선택한다면 join으로가져옴

JPA 구동방식

스크린샷 2023-04-06 오전 9.10.57

JPA 쓸때 주의해야 할점

  • 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유 (싱글톤)
  • 엔티티 매니저는 쓰레드간에 공유X (사용하고 버려야 한다). (트랜잭션 단위로 엔티티 매니저 쓴다!)
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행 (모든 RDB내부에서도 트랜잭션 단위로 일어남, JPA도 동일하게 설계됨)(ex. 더티체킹)

JPQL 소개

  • JPA를 사용하면 엔티티 객체를 중심으로 개발
  • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검 색 조건이 포함된 SQL이 필요
  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공 (dialect만 바꾸면 모든 DB에 맞춰 SQL번역됨)
  • SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리

JPA 설정 예시

  • dependency

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.3.10.Final</version>
    </dependency>
    <!-- H2 데이터베이스 -->
    <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.199</version>
    </dependency>
  • src/main/resources/META-INF/persistence.xml

    • jdbc driver, 및 DB 설정
    • persistence-unit name="hello" 이름은 추후 EntityManagerFactory 를 생성시 name으로 사용
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="hello">
    <properties>
    <!-- 필수 속성 -->
    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
    <property name="javax.persistence.jdbc.user" value="sa"/>
    <property name="javax.persistence.jdbc.password" value=""/>
    <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    <!-- 옵션 -->
    <property name="hibernate.show_sql" value="true"/>
    <property name="hibernate.format_sql" value="true"/>
    <property name="hibernate.use_sql_comments" value="true"/>
    <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
    </properties>
    </persistence-unit>
    </persistence>
  • EntityManagerFactory 생성 -> Spring에서 단 한개만 존재 싱글톤

  • EntityManager 생성 -> 트랜잭선 단위로 생선한다고 생각

  • 예시

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // 한번만 소환

    EntityManager em = emf.createEntityManager(); // 한트랜잭션 당 하나만 만들기

    EntityTransaction tx = em.getTransaction();
    tx.begin();
    try {
    // Member member = em.find(Member.class, 1L);
    List<Member> result = em.createQuery("select m from Member as m", Member.class)
    .setFirstResult(2)
    .setMaxResults(5)
    .getResultList();

    for (Member member:result){
    System.out.println("member = " + member);
    }


    tx.commit();
    }
    catch (Exception e){
    tx.rollback();
    } finally {
    em.close();
    }

    emf.close();
CATALOG
  1. 1. 왜?
  2. 2. 출처
  3. 3. 목표
  4. 4. JPA 기본
  5. 5. JPA 란?
  6. 6. JPQL 소개
  7. 7. JPA 설정 예시