JPA 시작

윤용운·2022년 3월 23일
1

JPA_스터디

목록 보기
2/9
post-thumbnail

2장. JPA 시작

프로젝트 세팅

책에서는 Eclipse로 진행하지만, 깔기 귀찮으므로 IntelliJ에서 진행하였다.

IntelliJ에서 Maven 프로젝트 생성

H2 데이터베이스 설치

1.4.198 버전 이후로는 보안문제로 데이터베이스가 자동 생성되지 않기 때문에 데이터베이스를 직접 생성해야 한다.

brew install h2
h2

  • Embedded 모드로 연결 시험 후, Server모드로 실행하면 정상적으로 동작한다. (안되면 껏다가 다시 켜보자)

  • 예제 테이블 생성

라이브러리와 프로젝트 구조

  • Maven
    자바용 프로젝트 관리 도구 관리 도구로, 라이브러리 관리기능, 빌드 기능 등이 포함되어 있다.
  • pom.xml
    Maven의 설정 파일이다.
<?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>org.example</groupId>
    <artifactId>JPA_STUDY</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.6.5.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.210</version>
        </dependency>
    </dependencies>
</project>

객체 매핑 시작

package jpabook.start;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "MEMBER")
public class Member {

    @Id
    @Column(name = "ID")
    private String id;
    @Column(name = "NAME")
    private String username;
    // 매핑 정보가 없는 필드
    private Integer age;

    public String getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
  • @Entity
    해당 클래스를 테이블과 매핑한다는 것을 JPA에 알려준다. 이를 엔티티 클래스 라고 한다
  • @Table
    엔티티 클래스에 매핑할 테이블 정보를 알려준다. name속성을 통해 Member 엔티티를 MEMBER 테이블에 매핑하였으며, 생략시 클래스 이름을 테이블 이름으로 매핑한다.
  • @Id
    Pirmary Key(기본키)를 매핑한다. @Id가 사용된 필드를 식별자 필드라고 한다.
  • @Column
    필드를 컬럼에 매핑한다. name 속성을 사용해 Member 엔티티의 username 필드를 MEMBER 테이블의 NAME 컬럼에 매핑하였다.
  • 매핑 정보가 없는 필드
    매핑 어노테이션이 생략되면, 필드명을 사용해서 컬럼명으로 매핑한다. 데이터베이스가 대소문자를 구분한다면 name 속성으로 명시적으로 매핑하여야 한다.

persistence.xml 설정

  • JPA는 persistence.xml을 사용하여 필요한 설정 정보를 관리한다. /META-INF/persistence.xml 클래스 패스 경로에 있다면, 별도의 설정 없이 JPA가 인식한다.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
    <persistence-unit name="jpabook">
        <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.id.new_generator_mappings" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="create"/>

            <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>
</persistence>
  • <persistence-unit name="jpabook">
    JPA는 영속성 유닛이라는 것부터 시작하는데 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록한다. name 속성으로 고유한 이름을 부여한다.
  • <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
    데이터베이스 방언 설정

    데이터베이스 방언이란?
    SQL표준을 지키지 않거나, 특정 데이터베이스만의 고유한 기능. Hibernate를 포함한 대부분의 JPA 구현체 에서는 특정 데이터베이스에 종속되지 않게 하기 위해 다양한 데이터베이스 방언 클래스를 제공한다.

어플리케이션 개발

package jpabook.start;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        // 엔티티 매니저 팩토리 생성
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
        // 엔티티 매니저 생성
        EntityManager em = emf.createEntityManager();
        // 트랜잭션 획득
        EntityTransaction tx = em.getTransaction();

        try {
            tx.begin();             // 트랜잭션 시작
            logic(em);              // 비지니스 로직 실행
            tx.commit();            // 트랜잭션 커밋
        } catch (Exception e) {
            tx.rollback();          // 트랜잭션 롤백
        } finally {
            em.close();             // 엔티티 매니저 종료
        }
        emf.close();                // 엔티티 매니저 팩토리 종료
    }

    public static void logic(EntityManager em) {
		
        String id = "id1";
        Member member = new Member();
        member.setId(id);
        member.setUsername("지한");
        member.setAge(2);

        //등록
        em.persist(member);

        //수정
        member.setAge(20);

        //한 건 조회
        Member findMember = em.find(Member.class, id);
        System.out.println("findMember=" + findMember.getUsername() + ", age=" + findMember.getAge());

        //목록 조회
        List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
        System.out.println("members.size=" + members.size());

        //삭제
        em.remove(member);
    }
}

엔티티 매니저 설정

  • EntityManagerFactory 생성
    persistence.xml의 설정 정보를 사용해 EntityManagerFactory를 생성한다. EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook"); 에서 META-INF/persistence.xml에서 이름이 jpabook인 영속성 유닛을 찾아서 EntityManagerFactory를 생성한다. 이때 JPA를 동작시키키 위한 기반 객체 생성, 그리고 구현체에 따라서 DB 커넥션 풀도 생성하므로 생성하는 비용이 아주 크다. 따라서 EntityManagerFactory는 어플리케이션에 따라서 딱 한번만 생성하고 공유해야 한다.

  • EntityManager 생성
    EntityManager em = emf.createEntityManager(); 에서 EntityManager를 생성한다. JPA의 대부분 기능은 EntityManager가 제공하고(등록, 수정, 삭제, 조회 등), 내부에서 데이터소스(데이터베이스 커넥션)을 유지하면서 데이터베이스와 통신한다. EntityManager는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안된다.

  • 종료
    사용이 끝난 EntityManager, 그리고 EntityManagerFactory는 다음과 같이 종료해야 한다.

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

트랜잭션 관리

  • JPA 사용 시, 항상 트랜잭션 안에서 데이터를 변경해야 한다. 트랜잭션 API는 EntityTransaction tx = em.getTransaction(); 처럼 받아오며, 정상 동작시 커밋(commit), 예외 발생시 롤백(rollback) 한다.

비지니스 로직

  • 등록
String id = "id1";
Member member = new Member();
member.setId(id);
member.setUsername("지한");
member.setAge(2);

em.persist(member);

Member 엔티티를 생성하고, em.persist(member)를 실행하게 되면 JPA는 매핑 정보를 분석해 위의 SQL을 만들어 SQL에 전달한다.

  • 수정
member.setAge(20);

JPA는 값을 추적하는 기증을 갖추고 있으므로, setter로 값만 바꾸어줘도 UPDATE SQL을 생성해서 데이터에비스에 값을 변경한다.

  • 삭제
em.remove(20);

remove() 메소드 사용 시, JPA는 DELETE SQL을 생성해서 실행한다.

  • 한 건 조회
Member findMember = em.find(Member.class, id);

find() 메소드는 조회할 엔티티 타입과 @Id로 엔티티 하나를 조회 할 수 있다. 그리고 조회한 결과 값으로 엔티티를 생성해서 반환한다.

JPQL

  • JPA는 객체를 중심으로 개발하므로 검색을 할 때에도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
  • 엔티티를 검색하려면 모든 데이터를 엔티티로 변경한 다음 검색해야 하는데, 말이 안된다.
  • JPQL(Java Persistence Query Language)라는 쿼리 언어로 해결한다.

    JPQL은 엔티티 객체(클래스와 필드)를 대상으로 쿼리한다.

 List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();

  • 여기서의 Member는 MEMBER 테이블이 아닌, Member 객체를 뜻한다.
  • 자세한것은 10장에서.

Reference

  • 자바 ORM 표준 JPA 프로그래밍 (김영한)

0개의 댓글