[JPA 기초 부수기] JPA 환경 구성, 시작

CrackCo·2020년 10월 1일
0

JPA 기초 부수기

목록 보기
2/3
post-thumbnail

자바 서버 개발을 위한 JPA에 대해서 알아보고자 했다. 학습 내용은 자바 ORM 표준 JPA 프로그래밍 교재를 기반으로 작성했다.

📚데이터베이스 준비

데이터베이스 설치

MySQL, Oracle 등 주로 사용되는 데이터베이스를 설치해도 되지만 테스트로 사용하기엔 부담이 있다. 그러므로 설치가 필요 없고 실제로 테스트로 사용되기도 하는 H2 데이터베이스를 사용하겠다.

https://www.h2database.com에 들어가서 All platforms으로 내려받으면 설치 없이 사용할 수 있다. 압축을 풀고 bin/h2.bat을 실행하면 서버 모드로 실행할 수 있다. 그리고 웹 브라우저에서 localhost:8082로 접속하면 아래와 같은 화면을 볼 수 있다.

위 화면에서 왼쪽 위 언어를 한국어로 설정하고 JDBC URL을 jdbc:h2:tcp://localhost/~/test으로 수정한 후 연결을 선택하면 test 데이터베이스에 서버 모드로 접근한다.

예제 테이블 생성

예제로 사용하기 위한 테이블을 생성하자.

CREATE TABLE MEMBER(
    ID VARCHAR(255) NOT NULL,
    NAME VARCHAR(255),
    AGE INTEGER NOT NULL,
    PRIMARY KEY (ID)
)

🤔Maven 프로젝트

메이븐은 라이브러리 관리 도구이다. pom.xml에 사용할 라이브러리를 작성하면 라이브러리를 자동으로 내려받아 관리한다.

먼저 Maven 프로젝트를 생성하고 pom.xml을 아래와 같이 작성하여 의존성을 추가해준다.

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.crackco</groupId>
    <artifactId>02-jap-start</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <!-- encoding settings -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <!-- hibernate version -->
        <hibernate.version>4.3.10.Final</hibernate.version>
        <!-- h2 database version -->
        <h2db.version>1.4.187</h2db.version>
    </properties>

    <dependencies>
        <!-- hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <!-- h2 database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>${h2db.version}</version>
        </dependency>
    </dependencies>
</project>

<dependency> 안에 <groupId>, <artifactId>, <version>를 작성하면 Maven 저장소에서 내려받아 라이브러리에 자동으로 추가된다.

객체 매핑

클래스 작성

위에 작성한 Member 테이블의 내용으로 Member 클래스를 작성한다.

package jpabook.start;

/**
 * @author Woojo
 */

public class Member {

    private String id;
    private String username;
    private int age;

    // Getter, Setter
    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

그 다음 JPA에서 제공하는 매핑 어노테이션을 추가한다. 매핑 어노테이션을 추가하기 위해서 javax.persistenceimport하면 된다.

매핑 어노테이션

package jpabook.start;

import javax.persistence.*;

/**
 * @author Woojo
 */

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

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

    // Getter, Setter
    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

예제에서 사용한 매핑 어노테이션

  • @Entity
    해당 클래스를 테이블과 매핑을 명시, 해당 클래스를 엔티티 클래스라고 한다.
  • @Table
    엔티티 클래스에 매핑할 테이블 정보를 명시, name 속성을 사용하여 MEMBER 테이블에 매핑한다고 명시하였고 생략 시 클래스 이름과 같은 테이블에 매핑한다.
  • @Column
    필드를 컬럼에 매핑한다. name 속성을 사용하여 매핑할 컬럼명을 명시할 수 있다.
    생략 시 필드명과 같은 이름의 컬럼에 매핑한다.

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" /> -->
        </properties>
    </persistence-unit>

</persistence>

설정은 <persistence>로 xml의 네임스페이스와 사용할 버전을 지정한다.

JPA 설정은 <persistence-unit name="">으로 설정할 수 있으며 일반적으로 데이터베이스 하나당 등록한다. 또한 name속성을 사용하여 고유한 이름을 부여해야 한다.

데이터베이스와 연결을 위해서 <properties> 안에 각 <property>를 설정해주어야 한다.

  • JPA 표준 속성
    • javax.persistence.jdbc.driver: JDBC 드라이버
    • javax.persistence.jdbc.user: 데이터베이스 접속 사용자명
    • javax.persistence.jdbc.password: 데이터베이스 접속 비밀번호
    • javax.persistence.jdbc.url: 데이터베이스 접속 url
  • hibernate 속성
    • hibernate.dialect: 데이터베이스 방언 설정

JPA 프로젝트 Run

앞서 객체 매핑, persistence.xml을 작성하였으면 애플리케이션 개발을 위해서 main 메서드를 작성해주어야 한다.

package jpabook.start;

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(); // 엔티티 매니저 팩토리 종료
    }

    private static void logic(EntityManager em) {
    }

}

Entity Manager 설정

persistence.xml의 설정 정보를 기반으로 EntityManagerFactory를 생성한다. EntityManagerFactory는 단 한 번 생성하여 사용하고 마지막에 종료한다.

EntityManagerFactory를 사용하여 EntityManager를 생성할 수 있다. 대부분의 JPA 기능은 EntityManager가 제공하므로 데이터베이스의 조작을 수행하는 역할을 수행한다.

EntityManager는 데이터베이스 연결과 밀접한 관계가 있으므로 스레드간 공유하거나 재사용하면 안 된다.

트랜잭션 관리

JPA는 항상 트랜잭션 안에서 데이터를 조작해야 한다. 트랜잭션은 EntityManager의 API를 사용하여 EntityTransaction을 받아올 수 있다.

비즈니스 로직

private static void logic(EntityManager em) {
    String id = "id1";
    Member member = new Member();
    member.setId(id);
    member.setUsername("CrackCo");
    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);
}

// 출력
findMember=Crackco, 20
members.size=1

EntityManager 객체 em을 사용하여 데이터베이스 CRUD를 수행하는 코드이다.
대부분 EntityManager의 API를 사용하여 데이터를 조작하지만 Update는 객체를 수정할 뿐이다. 이는 JPA가 엔티티의 변경을 추측하는 기능을 갖추고 있기 때문에 자동으로 Update SQL을 수행한 결과이다.

JPQL

아래는 목록을 조회하는 코드이다.

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

JPA를 사용하는 개발자는 엔티티 객체를 중심으로 개발하고 데이터베이스 연동은 JPA에 맡기게 된다. 하지만 검색을 수행할 땐 모든 데이터를 불러와서 엔티티 객체로 변환하고 검색을 수행해야 한다. 이는 시스템에 매우 큰 부담을 주며 사실상 불가능에 가깝기 때문에 필요한 데이터를 검색하기 위해 검색 조건이 있는 SQL을 사용해야 한다. JPA에선 JPQL이라는 쿼리 언어를 사용하여 문제를 해결한다.

JPQL
SQL을 추상화한 객체 지향 쿼리 언어로 SQL과 문법이 비슷하다.
SQL과 차이점으로는 엔티티 객체를 대상으로 쿼리를 수행한다는 것이다.

profile
개발이 좋아서 개발자가 됐다.

0개의 댓글