본문 바로가기

JPA/JPA 시작

#01 JPA를 이용한 첫번째 애플리케이션

해당 포스팅은 김영한님의 JPA프로그래밍을 읽으면서 공부한 내용을 정리하는 포스팅이다. 

Spring Boot를 사용한다면 Spring Data JPA 를 바로 사용해도 좋지만 기본 원리는 알고 있다면 이슈 대응이나 기술에 대한 이해도 측면에서 좋을 것 같아서 우선 책에 나온 예제를 토대로 사용 기술을 정리할 예정이다.

 

(참고로 책에나온 설치과정이나 간단한 설정 부분은 다루지 않는다.  우리는 JPA가 무엇이고 어떻게 사용하며 어떤 클래스들이 있는지 익혀가는데 중점을 두고 포스팅 할 예정이다. )

 

Index

  • 프로젝트 구조
  • 엔티티 매니저 설정
  • 트랜잭션 관리
  • 비즈니스 로직
  • JPQL
  • 정리

프로젝트 구조

ch02-jpa-start1 프로젝트 구조

JpaMain.java

package jpabook.start;
 
import javax.persistence.*;
import java.util.List;
 
/**
 * @author holyeye
 */
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);
 
        //한 건 조회
        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);
 
    }
}
 

JpaMain.java : JPA를 이용한 CRUD 작업을 수행하는 main 메서드

 

Member.java

package jpabook.start;
 
import javax.persistence.*;  //**
 
/**
 * User: HolyEyE
 * Date: 13. 5. 24. Time: 오후 7:43
 */
@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;
    }
}
 

Member.java : 테이블과 메핑되는 클래스로 @Entity 어노테이션을 사용

 

persistence.xml

<?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 : 연결하려는 DB의 필수값과 선택값을 설정하는 파일

 

 

엔티티 매니저 설정

김영한님의 JPA프로그래밍 2.12 엔티티 매니저 설정

 

테스트 코드

 

"엔티티매니저설정" 이미지를 보면 Persistence 에서 시작한다. 그런데 잘 생각해보면 Persistence는 우리가 만든 클래스가 아니다. 우리는 javax.persistence 패키지에서 제공하는 클래스를 사용하게 된다.

 

1. persistence.xml 참조 - 가장먼저 수행하는 부분은 persistence.xml을 참조한다. 하지만 참조하는 부분을 아직 찾지 못했다. (강의에서 들었던 내용은 프로젝트의 META-INF 밑에 만들면 설정정보를 참조한다고 알고 있는데 아마 안쪽에 숨겨져 있는 것 같다. 이번 내용에서는 패스ㅠ)

 

2. EntityManagerFactory 생성 -  Persistence클래스의 createEntityManagerFactory 를 호출하면 우리는 EntityManagerFactory 를 얻을 수 있다.

(참고 - createEntityManagerFactory() 메소드를 호출하려면 매개변수로 String persistenceUnitName 을 넘겨줘야 된다. )

 

내부적으로 궁금해서 조금더 살펴봤더니 아래 흐름대로 호출하고 있다.

createEntityManagerFactory(String persistenceUnitName) ->

createEntityManagerFactory(String persistenceUnitName, Map properties) -> PersistenceProvider.createEntityManagerFactory(String emName, Map map)

 

마지막에 PersistenceProvider는 인터페이스이며 아래 이미지를 보면 PersistenceProvider의 createEntityManagerFactory를 호출한다. 그리고 이를 구현한 클래스들이 몇가지 있다. 

Persistence 클래스의 createEntityManagerFactory() 메서드

 

너무 깊이 들어가면 포스팅이 길어질 것 같아서 여기 까지만 확인하자... 중요한건 우리는 2번을 수행함 으로서 EntityManagerFactory 에서 우리가 최종적으로 사용할 EntityManger를 생성할 수 있게 된다는 것이다.

 

3. EntityManger 생성 - EntityManagerFactory 의 createEntityManager() 메서드로 EntityManger 를 얻을 수 있다. 

 

 

트랜잭션 관리

트랜젝션의 시작과 종료를 관리 해주는 EntityTransaction 인터페이스를 사용하고 있다. 해당 구현객체는 우리가 앞서 만들었던 EntityManager 에서 getTransaction()으로 얻을 수 있다.

EntityTransaction 인터페이스 안에는 여러가지 트랜젝션관리를 위한 메소드 존재하지만

우리가 이번에 사용하는 메소드는 아래의 두가지다. 

 

begin() : 트렌젝션 시작commit() : 트렌젝션 종료

 

이미지 "테스트 코드" 를 보면 트랜젝션을 시작하고 종료하는 부분을 볼 수 있다. 

그리고 그 사이에는 우리가 같은 트랜젝션 내에 수행할 코드를 작성해서 처리하면된다.

 

 

비즈니스 로직

비즈니스 로직

1. Member 객체에 id,username,age 를 set

2. EntityManager 객체의 persist(memeber) 를 이용해서 등록한다.

3. member.SetAge(20)을 하면 수정이 일어난다. (실제로 DB에 UPDATE 문 날림)

4. EntityManager 객체의 find(Member.class, id) 를 이용해서 id에 해당하는 member를 조회한다.

5. EntityManager 객체의 createQuery()를 통해서 JPQL을 작성하고 member리스트를 조회한다.

6. EntityManager 객체의 remove(member) 로 현재 객체를 DB에서 삭제한다.

 

우리가 일반 객체를 만들어서 set메소드를 호출하면 아무일도 일어나지 않지만

persist로 등록한 이후에 set메소드를 호출하면 DB에 해당 데이터를 자동으로 바꿔준다.

JPA가 일반 객체와 구분을 하는 것 같다. 

 

JPQL

JPQL  목록조회

JPQL ( Java Persistence Query Langugage ) : SQL을 추상화한 JPQL이라는 객체이향 쿼리 언어를 제공한다.

JPQL은 SQL과 문엉비 거의 유사해서 SELECT,FROM,WHERE,GROUP BY, HAVING, JOIN등을 사용할 수 있다. 둘의 가장 큰 차이점은 다음과 같다.

 

  • JPQL은 엔티티 객체를 대상으로 쿼리한다. 쉽게 이야기해서 클래스와 필드를 대상으로 쿼리한다.
  • SQL은 데이터베이스 테이블을 대상으로 쿼리한다.

여기서 재미 있는건 JPQL은 데이터베이스의 테이블을 전혀 알지 못한다는 것이다.  결국 

목록조회에 사용한 "select m from Member m" 에서 Member는 회원 엔티티 객체를 말하는 것이다.

JPA는 JPQL을 분석해서 아래와 같은 쿼리로 데이터 베이스에서 조회 한다.

 

SELECT M.ID

        , M.NANE

        , M.AGE

 FROM MEMBER M

 

정리

간단하게 위에서 봤던 아래의 이미지를 다시보자

김영한님의 JPA프로그래밍 2.12 엔티티 매니저 설정

이 이미지 하나면 충분할 것 같다...  누가 누구를 생성하게 해주는지 알면 끝!! 어차피 반복 작업이라서 아마도 Spring Data JPA는 지금 수행한 단계를 많이 줄여줄 것 같다. 

그리고 또 하나는 EntityTransaction 을 EntityManager에서 얻을수 있다는 것만 알면 이번 예제는 어느정도 정리가 끝난 것 같다. ! 

개인적인 생각으로 SQL에 있어서 조회때 일어나는 여러가지 단점을 보완하고 해결하기 위해서 JPQL이 나온것 같다.

우리를 SQL로 부터 완전히 분리시키고 싶다는게 보인다.  아마 100% JPA만 사용할 수는 없을 것 같지만 나보다 훨씬 뛰어난 엔지니어들이 고민하고 또 고민해서 만든 기술이고 세계적으로 90%이상이 JPA를 사용한다고 하니까 분명

엄청난 이점을 가지고 있는건 확실한 것 같다.