본문 바로가기

Dev/JPA

JPA의 사용

여기서는 직접 사용해보고 이해한 내용을 중심으로 풀어보고자 한다.


사용 환경

  • IDE : Intelij
  • DB : h2 database
  • 의존성 관리 : Maven
  • Java 8

1. 라이브러리 추가 (pom.xml)

JPA를 사용하려면 위와같은 라이브러리가 필요하다.

Maven을 사용하여 자동으로 다운받아지도록 Pom.xml에 추가해주자!

  1. JPA의 인터페이스로 하이버네이트를 선택함 
  2. 내가 사용할 데이터베이스(h2)

여기서 중요한 것은 내가 다운받은 데이터베이스 버전이랑 동일한 버전으로 설정해야한다는 점!

2. JPA 설정하기 (persistence.xml)

어떤거는 javax로 시작하고, 어떤것은 hibernate로 시작하는 설정인데..

이부분은 쉽게 말해서 앞에서 JPA를 쓰기위해서 사용하는 구현체가 여러개로 나뉘어 지는데

  • javax로 설정한 것은 구현체가 바뀌어도 상관없이 쓸수있는 말그대로 공통적인 설정의 의미이고
  • hibernate로 시작되는 것은 JPA를 사용하기위한 구현체 중에서도 hibernate로만 설정해서 쓰는 것들이다.
  • persistence.xml 파일 내용
  • JPA를 사용하기 위해서는 하이버네이트 라이브러리만 넣는다고 되는것이 아니라 JPA를 사용하겠다는 설정을 넣어줘야 함
  • 보통 JPA 설정파일의 위치는 정해져있다 (META-INF/persistence.xml)

3. 데이터베이스 방언 (특정 데이터베이스만의 고유한 기능)

  • JPA는 특정 데이터베이스에 종속적이지 않음 / dialect를 이용해서 각 데이터베이스에 맞게 맞춰서 사용하면 됨 (Mysql Dialect, Oracle Dialect, h2Dialect)
  • 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 차이가 있음
  • 가변 문자 : Mysql은 VARCHAR, Oracle은 VARCHAR2
  • 문자열을 자르는 함수 : SQL표준은 SUBSTRING(), Oracle은 SUBSTR()
  • 페이징 처리 : Mysql은 LIMIT, Oracle은 ROWNUM
    • 이부분이 제일 문제가 되어 고려해야 할 수 있다. 즉 페이징 처리하는 문법이 다르기 때문에 JPA입장에서는 바뀔때마다 자동으로 바꿔줘야하기때문에 방언이 꼭 필요하다.

즉 JPA는 각 데이터베이스가 가지고있는 특징에 맞춰서 자동으로 변형해서 사용하게 해준다! 라는 뜻 ... 마치 이놈처럼 말이지!

 

메타몽(나 모르는사람 없제?)


3. JPA 구동 방식

JPA의 구동방식


그림만 봤을 때 위와 같은 표정을 짓고 있는 사람들이 있을 수 있으니 내가 이해한 것을 토대로 알기 쉽게 코드랑 해서 비유해줄게!


다들 이게임은 한번쯤 해봤겠지?

참고로 필자는 프로토스를 주종족으로 플레이 했었어 이게임으로 비유해볼려고 해

스타크래프트


맵 이미지 (Persistence.xml을 가져와서 사용)

  • 나는 빠른 무한 맵을 선택해서 플레이 하려고 해 ... 여기서 사전에 나는 이 맵을 할거라고 골라야 하잖아?
  • 이게 JPA를 사용하기위해 Persistence.xml 설정을 불러와서 Persistence를 생성하는거랑 같아.

넥서스 = EntityManagerFactory

  • 프로토스 종족의 제일 기본 건물인 넥서스야 여기에서 일꾼을 뽑아야 하지 ... 넥서스는 여러개 지을수 있는데 여기서는 한개만 지을 수 있다고 가정할게..
  • 코드로 풀어보면 아래와 같이 작성 할 수 있어
  • EntityManagerFactory는 데이터베이스 마다 한개만 만들어서 사용하게 돼
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

프로브 = EntityManager

  • 이제 넥서스에서 일꾼을 뽑아야 하잖아 ... 이녀석이 프로브(일꾼)이야
  • 코드로 나타내면 아래와 같이 작성 할 수 있어
  • emf.createEntityManager()를 통해 EntityManager(프로브)를 만들어 내는 거야
EntityManager em = emf.createEntityManager();

게이트웨이

이제 프로브(EntityManager)를 통해 병력을 뽑아야하므로 게이트웨이라는걸 지어야해

근데 여기서 문제가 있어! ... 지을 수가 없거든 왜냐고?? 이녀석이 없거든...


파일럿 = EntityTransaction

  • 프로토스 종족은 이 파일럿이라는 녀석을 지어줘야 게이트웨이라는 병력뽑는 건물을 지을 수 있어
  • 코드로는 다음과 같이 표현할 수 있어
  • EntityManager(프로브)는 em.getTransaction() 을 통해서 파일럿(Transaction)을 만들어 줘야해 .. 그리고 tx.begin() 하는순간 다 지어졌으니까 이제 건물 지을 수 있어! 라는거를 알려주는거야
  • JPA는 기본적으로 어떠한 변경이 이루어 진다면 트랜잭션 범위 안에서 이루어져야해! 이점 명심하자!
  • tx.begin()을 시작으로 아래에 tx.commit() 하는순간 범위내에 작업이 이루어지는거야
EntityTransaction tx = em.getTransaction();
tx.begin();
tx.commit();

다시 돌아와서 병력을 뽑아주는 게이트웨이라는 건물을 지어야 해

EntityManager(프로브)에게 persist라는 명령을 줘서 아래와 같이 건물을 생성했어

em.persist(member);


이제 병력을 뽑아 내야하는데 다양한 명령들이 존재해

코드로 정리하면 아래와 같이 표현할 수 있어

Member findMember = em.find(Member.class, 1L); // 질럿(유닛)을 뽑아줘!
findMember.setName("HelloJPA"); // 질럿뽑을려고 했는데 드라군 뽑아야할거같아 수정해줘
findMember.remove(member); // 돈을 좀 아껴야할거같아 다 취소해줘

여기까지 비유해서 쭉 설명해보았고 전체적인 코드는 아래에 있으니 참고해서 확인하면 돼!

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

public class JpaMain {
    public static void main(String[] args) {
        // EntityManagerFactory는 웹서버가 올라왔을 떄 디비당 딱 하나만 생성해야 한다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // 고객의 요청이 올때마다 계속 썼다가 em.close로 버렸다가 해야함 -> 매니저는 쓰레드간에서 공유하면 안된다!!! 사용하고 버려야하는 개념
        EntityManager em = emf.createEntityManager();

        //code 작성 부분
        // JPA의 모든 변경은 무조건 트랜잭션 안에서 이루어져야한다.
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            Member member = new Member();
//            // JPA에서는 트랜잭션 단위가 엄청 중요하다.
//            // 무언가 데이터에 변화가 생기게되면

			em.persist(member); // Insert시 사용

            Member findMember = em.find(Member.class, 1L);
            findMember.setName("HelloJPA");
            
            // commit을 꼭 해줘야한다. 해주지 않으면 반영이 안됨
            tx.commit();
        }catch(Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

'Dev > JPA' 카테고리의 다른 글

RS) JPA(Java Persistence API)  (0) 2022.02.01
RS) SQL 중심적인 개발의 문제점  (0) 2022.02.01
프록시와 연관관계 관리  (0) 2020.08.08
JPA 상속관계 매핑  (0) 2020.07.30
다양한 연관관계 매핑  (0) 2020.07.28