2. JPA 시작하기

HotFried·2023년 9월 25일
0

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jpabook</groupId>
    <artifactId>jpashop</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- JPA 하이버네이트 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.13.Final</version>
        </dependency>
        <!-- H2 데이터베이스 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

    </dependencies>

</project>

✓ Java 11
✓ Maven
✓ groupId: jpa-basic
✓ artifactId: ex1-hello-jpa
✓ version: 1.0-SNAPSHOT

persistence.xml

<?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/~/jpashop;MODE=MySQL"/>
            <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.jdbc.batch_size" value="10"/>
            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>
</persistence>

✓ 경로 : resources/META-INF/persistence.xml

링크 : hibernate.hbm2ddl.auto 설정


사투리, 방언(dialect)

  • SQL 표준을 지키지 않는 특정 DB만의 고유한 기능

  1. JPA는 특정 DB에 종속되지 않는다. (자바 ORM 표준 JPA 프로그래밍 예제는 H2 Database 사용)
  2. 각각의 DB가 제공하는 SQL 문법과 함수가 조금씩 다르다. JPA가 번역해서 db에 전달한다.

애플리케이션 개발

JPA 구동 방식

  1. JPA의 Persistence 클래스가 META-INF/persistence.xml 설정 정보를 조회한다.
  2. EntityManagerFactory 클래스를 생성한다.
  3. 팩토리에서 필요할 때 마다 EntityManager를 생성한다.

회원 생성

create table Member
(
    id   bigint not null,
    name varchar(255),
    primary key (id)
);

JpaMain.java

public class JpaMain {

    public static void main(String[] args) {
        // EntityManagerFactory는 애플리케이션 로딩 시점에 하나만 만들어야 한다.
        // persistence.xml에서 설정했던 'persistence-unit name' 값을 넘긴다.
        // 예제에서는 "hello"로 설정했다.
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");

        // EntityManager는 트랜잭션마다 만들어줘야 한다.
        EntityManager entityManager = entityManagerFactory.createEntityManager();

        // JPA의 모든 작업은 트랜잭션 내에서 해야 적용된다.
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setId(1L);
            member.setName("helloA");

            // 저장
            entityManager.persist(member);

            // commit 시 Query가 DataBase로 전달된다.
            tx.commit();
        } catch (Exception e) {
            // 실패 시 롤백
            tx.rollback();
        } finally {
            // EntityManager 꼭 닫기
            entityManager.close();
        }

        // 전체 애플리케이션이 끝나면 팩토리까지 닫는다.
        entityManagerFactory.close();
    }
}

Member.java

@Entity
public class Member {

    // PK를 지정
    @Id
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

JpaMain.java 실행 시 아래와 같은 쿼리가 작성된다.

Hibernate:
    insert into Member(name, id) values(?, ?)

회원 수정

JpaMain.java

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();

        try {
            // 1차 캐시에 존재하지 않을 경우 DB에서 조회
            Member findMember = entityManager.find(Member.class, 1L);

            System.out.println("id: " + findMember.getId());
            System.out.println("name: " + findMember.getName());

            findMember.setName("JPA");

            // 수정한 객체를 따로 저장하지 않아도, commit시점에 업데이트 쿼리를 생성한다. 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            entityManager.close();
        }

        entityManagerFactory.close();
    }
}

JpaMain.java 실행 시 아래와 같은 쿼리가 작성된다.

update Member set name=? where id=?

주의사항

  1. EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유하도록 한다.
  2. EntityManager는 쓰레드간에 공유하지 않는다.(사용하고 버려야 한다.)
    • 요청 발생 시 EntityManager를 사용하고 버리는 작업을 반복
  3. JPA의 모든 데이터 변경은 트랜잭션 안에서 실행

JPQL

  • 가장 단순한 조회 방법
    1. EntityManager.find()
    2. 객체 그래프 탐색 : a.getB().getC()

예제

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();

        try {
            // JPA는 DB가 아닌 객체를 대상으로 Query를 작성한다.
            // 객체를 대상으로 쿼리를 짜기 때문에
            // 여기서 Member는 테이블이 아니라 객체를 가리킨다.
            List<Member> result = entityManager
                    .createQuery("select m from Member as m", Member.class)
                    // 페이지네이션을 할 수도 있다. 아래는 1번부터 10개 가져온다.
                    .setFirstResult(1)
                    .setMaxResults(10)
                    .getResultList();

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

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

        entityManagerFactory.close();
    }
}

JPQL의 특징

  • JPA를 사용하면 Entity 객체를 중심으로 개발한다.

  • 검색 또한 테이블이 아닌 Entity 객체를 대상으로 한다.

  • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다.

  • 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
    -> 이때 객체를 대상으로 검색할 수 있게 하는 기술이 JPQL이다.


  • JPQL은 Entity 객체를 대상으로 쿼리 & SQL은 DB 테이블을 대상으로 쿼리
    -> JPQL은 객체를 대상으로 검색하는 객체 지향 쿼리

  • SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다 (방언).

참고 :

김영한. 『자바 ORM 표준 JPA 프로그래밍』. 에이콘, 2015.

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

profile
꾸준하게

0개의 댓글