JPA 시작

2023. 4. 27. 11:06JPA

반응형

JPA를 사용해서 테이블 하나를 등록/수정/삭제/조회하는 간단한 JPA 애플리케이션을 만들어본다.

JPA는 필요한 라이브러리도 많고 데이터베이스도 필요하다. 그리고 자바 IDE(Integrated Development Environment)없기 개발하기 힘들다.

JPA를 사용하기 위한 과정

 

1) 이클립스 설치와 프로젝트 불러오기

IDE는 가장 많은 자바 개발자들이 사용하는 이클립스를 설치한다.

이때 될 수 있으면 Eclipse for Java EE Developers 패키지로 내려받는 것을 권장한다. -> JPA로 개발할 때 편리한 도구들이 지원됨.

프로젝트를 import해서 불러온다. 메이븐 프로젝트를 사용할것임.

프로젝트를 처음 불러오면 메이븐 저장소에서 라이브러리를 내려받기 때문에 1~10분정도 시간이 소요된다.

메이븐은 따로 설치가 되어야하는데 내려받은 이클립스 버전에는 메이븐이 내장되어있어서 별도로 설치하지 않아도 된다.

2) 예제 테이블 생성

<회원 테이블>

CREATE TABLE MEMBER {
    ID VARCHAR (255) NOT NULL,  /* 아이디(기본 키) */
    NAME VARCHAR (255),         /* 이름 */
    AGE INTEGER NOT NULL,       /* 나이 */
    PRIMARY KEY (ID)
)
 

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

JPA 구현체로 하이버네이트를 사용한다.

<핵심 라이브러리>

· hibernate-core: 하이버네이트의 핵심 라이브러리

· hibernate-entitymanager: 하이버네이트가 JPA 구현체로 동작하도록 JPA 표준을 구현한 라이브러리

· hibernate-jpa-2.1-api: JPA 2.1 표준 API를 모아둔 라이브러리

예제에서 사용할 프로젝트 구조는 다음과 같다.

src/main

|ㅡ java

| |___ jpabook/start

| |_____ JpaMain.java (실행 클래스)

| |_____ Member.java (회원 엔티티)

|ㅡ resources

| |_____ persistence.xml (JPA 설정 정보)

pom.xml

4)메이븐과 사용 라이브러리 관리

메이븐: 라이브러리를 관리해주는 도구이다. pom.xml에 사용할 라이브러리를 적어주면 라이브러리를 자동으로 내려받아서 관리해준다.

<메이븐의 설정 파일 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>ch02-jpa-start1</artifactId>
	<version>1.0-SNAPSHOT</version>

	<properties>

		<!-- 기본 설정 -->
		<java.version>1.6</java.version>
		<!-- 프로젝트 코드 인코딩 설정 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- JPA, 하이버네이트 버전 -->
		<hibernate.version>4.3.10.Final</hibernate.version>
		<!-- 데이터베이스 버전 -->
		<h2db.version>1.4.187</h2db.version>

	</properties>


	<dependencies>
		<!-- JPA, 하이버네이트 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<!-- H2 데이터베이스 -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>${h2db.version}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

5) 객체 매핑 시작

<회원 클래스>

package jpabook.start;

import javax.persistence.*; 

@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;
    }
}

이것으로 매핑 작업을 완료했다. 매핑 정보 덕분에 JPA는 어떤 엔티티를 어떤 테이블에 저장해야 하는지 알 수 있다.

6) 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" />  <!-- 하이버네이트가 실행한 sql을 출력 -->
            <property name="hibernate.format_sql" value="true" />  <!-- 하이버네이트가 실행한 sql을 보기쉽게 정렬--> 
            <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>

7) 애플리케이션 개발

객체 매핑을 완료하고 persistence.xml로 JPA 설정도 완료했다.

아래 코드는 크게 3부분으로 나뉘어져있다.

· 엔티티 매니저 설정

· 트랜잭션 관리

· 비즈니스 로직

package jpabook.start;

import javax.persistence.*;
import java.util.List;

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) { //예외 발생 시 트랜잭션을 롤백
            e.printStackTrace(); //예외를 결과화면에 출력
            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); //jpa는 어떤 엔티티가 변경되었는지 추적하는 기능

        //한 건 조회
        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);

    }
}

-엔티티 매니저 설정

▼ 엔티티 매니저 팩토리 생성

JPA를 시작하려면 우선 persistence.xml의 설정 정보를 사용해서 엔티티 매니저 팩토리를 생성해야한다. 이때 Persistence클래스를 사용하는데 이 클래스는 엔티티 매니저 팩토리를 사용해서 JPA를 사용할 수 있게 준비한다. 엔티티 매니저 팩토리를 생성하는 비용은 아주 크므로, 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한번만 생성하고 공유해서 사용해야 한다.

▼ 엔티티 매니저 생성

엔티티 매니저 팩토리에서 엔티티 매니저를 생성한다. JPA의 기능 대부분은 이 엔티티 매니저가 제공한다. 대표적으로 엔티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다. 엔티티 매니저는 내부에 데이터소스(데이터베이스 커넥션)을 유지하면서 데이터베이스와 통신한다. 따라서 애플리케이션 개발자는 엔티티 매니저를 가상의 데이터베이스로 생각할 수 있다. 참고로 엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안 된다.

▼종료

마지막으로 사용이 끝난 엔티티 매니저는 다음처럼 반드시 종료하여야한다.

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

애플리케이션을 종료할 때 엔티티 매니저 팩토리도 다음처럼 종료해야 한다.

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

-트랜잭션 관리

JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 한다. 트랜잭션 없이 데이터를 변경하면 예외가 발생한다. 트랜잭션을 시작하려면 엔티티 매니저에서 트랜잭션 API를 받아와야 한다.

-비즈니스 로직

비즈니스 로직은 단순하다. 회원 엔티티를 하나 생성한 다음 엔티티 매니저를 통해 데이터베이스에 등록, 수정, 삭제, 조회한다.

JPQL

 

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

JPA를 사용하면 애플리케이션 개발자는 엔티티 객체를 중심으로 개발하고 데이터베이스에 대한 처리는 JPA에 맡겨야한다. 바로 앞에서 살펴본 등록, 수정, 삭제, 한건 조회 예를 보면 SQL을 전혀 사용하지 않았다. 문제는 검색 쿼리다. JPA는 엔티티 객체를 중심으로 개발하므로 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.

그런데 테이블이 아닌 엔티티 객체를 대상으로 검색하려면 데이터베이스의 모든 데이터를 애플리케이션으로 불러와서 엔티티 객체로 변경한 다음 검색해야하는데 사실상 이는 불가능하다. 애플리케이션이 필요한 데이터만 데이터베이스에서 불러오려면 결국 검색조건이 포함된 SQL을 사용해야한다. JPA는 JPQL이라는 쿼리 언어로 이를 해결한다.

JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리 언어를 제공한다. JPQL은 SQL과 문법이 거의 유사해서 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 등을 사용할 수 있다. 둘의 가장 큰 차이점은 JPQL은 엔티티 객체를 대상으로 쿼리하고, SQL은 데이터베이스 테이블을 대상으로 쿼리한다.

select m from Member m -> 이 부분이 JPQL, 여기서 Member는 데이터베이스 테이블이 아닌 엔티티 객체임.

createQuery을 통해서 쿼리객체를 생성한 후, 쿼리 객체의 getResultList() 메소드 호출.

참고로 JPQL은 대소문자를 명확하게 구분 함.

정리

 

JPA를 사용하기 위한 개발 환경을 설정하고, JPA를 사용해서 객체 하나를 테이블에 등록/수정/삭제/조회하는 간단한 애플리케이션을 만들어보았다. JPA가 반복적인 JDBC API와 결과 값 매핑을 처리해준 덕분에 코드량이 상당히 많이 줄어든 것은 물론이고 심지어 SQL도 작성할 필요가 없었다. 하지만 코드량을 줄이고 SQL을 자동 생성하는 것은 JPA가 제공하는 전체 기능 중 일부에 불과하다. 다음엔 JPA의 핵심 기능인 영속성 관리에 대해 알아보겠다.

 

반응형

'JPA' 카테고리의 다른 글

연관관계 매핑 기초  (0) 2023.04.27
엔티티 매핑  (0) 2023.04.27
영속성 관리 (2)  (0) 2023.04.27
영속성 관리 (1)  (0) 2023.04.27
JPA 소개  (0) 2023.04.27