본문 바로가기

IT공부/JPA

JPA 2강 - JPA기초와 매핑

JPA 2강 - JPA기초와 매핑

JPA에서 중요한 게 2가지가 있다. 

1. 객체와 RDB를 중간에서 매핑하는 과정(설계)

2. JPA 동작 원리(영속성 컨텍스트)

Hello JPA

H2 데이터베이스

  • http://www.h2database.com/
  • 최고의 실습용 DB (테스트용으로 쓰기 좋다.)
  • 가볍다. (1.5M)
  • 웹용 쿼리툴 제공
  • MySQL, Oracle 데이터베이스 시뮬레이션 기능
  • 시퀀스, AUTO INCREMENT 기능 지원

메이븐 설정

  • https://maven.apache.org/
  • 자바 라이브러리, 빌드 관리
  • 라이브러리 자동 다운로드 및 의존성 관리

객체 매핑하기

  • @Entity : JPA가 관리할 객체(엔티티라고 한다.)

@Entity

public class Member {

   

   @Id

    private Long id;

    private String name;

    ...

}

 

  • @Id : DB PK와 매핑할 필드

create table Member (

   id bigint not null,

   name varchar(255),

   primary key (id)

)

persistence.xml

  • JPA 설정 파일
  • /META-INF/persistence.xml 위치
  • javax.persistence로 시작 : JPA 표준 속성
  • hibernate로 시작 : 하이버네이트 전용

persistence.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
  3.  
  4.     <persistence-unit name="jpabook">
  5.  
  6.         <properties>
  7.  
  8.             <!-- 필수 속성 -->
  9.             <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
  10.             <property name="javax.persistence.jdbc.user" value="sa"/>
  11.             <property name="javax.persistence.jdbc.password" value=""/>
  12.             <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/./test"/>
  13.             <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
  14.  
  15.             <!-- 옵션 -->
  16.             <property name="hibernate.show_sql" value="true" />
  17.             <property name="hibernate.format_sql" value="true" />
  18.             <property name="hibernate.use_sql_comments" value="true" />
  19.             <property name="hibernate.id.new_generator_mappings" value="true" />
  20.  
  21.             <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
  22.         </properties>
  23.     </persistence-unit>
  24.  
  25. </persistence>

 persistence.xml에는 데이터베이스 접속정보, 옵션등을 넣어주면 된다. 라인 9 ~ 12는 데이터베이스 접속정보이다. property 태그의 name 속성을 "javax.persistence"로 시작하는 것은 JPA에서 표준화 한 것이고, "hibernate.dialect"는 하이버네이트에서만 쓸 수 있는 것이다. "dialect"는 방언이라는 뜻이다. 

데이터베이스 방언

  • JPA는 특정 데이터베이스에 종속적이지 않은 기술
  • 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다르다. 
  • 가변문자 : MySQL은 VARCHAR, Oracle은 VARCHAR2
  • 문자열을 자르는 함수 : SQL 표준은 SUBSTRING(), Oracle은 SUBSTR()
  • 페이징 : MySQL은 LIMIT, Oracle은 ROWNUM
  • 방언 : SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능

예를 들어 JPA에서 페이지 API를 호출하면 데이터베이스 Dailect에 따라서 완전히 다른 쿼리가 나온다. 그거를 JPA를 쓰기전에는 개발자가 DB마다 작성을 해줬지만 Dialect가 다 해준다. 

데이터베이스 방언

  • hibernate.dialect 속성에 지정
  • H2 : org.hibernate.dialect.H2Dialect
  • Oracle 10g : org.hibernate.dialect.Oracle10gDialect
  • MySQL : org.hibernate.dialect.MySQL5InnoDBDialect
  • 하이버네이트는 45가지 방언 지원

실습

h2 데이터베이스 쿼리툴을 아래와 같이 띄운다. 

테이블을 생성한다.( ctrl + enter로 쿼리 실행)

member 테이블 생성 후 아래와 같이 select 쿼리를 날려 아래와 같이 결과가 나오면 된다.

이번에는 이클립스에서 IDE를 띄워보자.

그 다음 Package Explorer 빈 공간에서 마우스 우클릭 > NEW > Other > Maven 검색 > Maven Project 선택 후 Next > Create a simple project 체크 Next > Group.id : hello.jpa / Artifact.id : hello.jpa Finish 

완료되면 hello.jpa라는 프로젝트가 만들어진다. 표준 메이븐 아키텍처 구조가 생성이 된 것이다. 

pom.xml 파일을 열고 아래와 같이 작성 후 저장하자.

 

pom.xml

  1. <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">
  2.   <modelVersion>4.0.0</modelVersion>
  3.   <groupId>hello.jpa</groupId>
  4.   <artifactId>hello.jpa</artifactId>
  5.   <version>0.0.1-SNAPSHOT</version>
  6.   <dependencies>
  7.         <dependency>
  8.                <groupId>org.hibernate</groupId>
  9.                <artifactId>hibernate-entitymanager</artifactId>
  10.                <version>5.3.7.Final</version>
  11.         </dependency>
  12.         <dependency>
  13.                <groupId>com.h2database</groupId>
  14.                <artifactId>h2</artifactId>
  15.                <version>1.4.197</version>
  16.         </dependency>
  17.   </dependencies>
  18. </project>

라인 9 "hibernate-entitymanager"를 넣으면 나머지 라이브러리가 자동으로 해결된다. 라인 10에서는 5.3.7.Final 버전을 사용하고 있는데 이 버전은 내부적으로 JPA 2.1 버전을 쓴다. 라인 13 ~ 15는 H2 데이터베이스 라이브러리이다. 라인 15에서 버전이 1.4.197로 되어 있는데 로컬에 다운받은 H2 버전과 맞지 않으면 실행이 안될 수 있다. 

위와 같이 작성후 아래와 같이 라이브러리를 정상적으로 다운로드 했는지 확인해보자.

pom.xml에 Dependency Hierachy 탭을 보자. "hibernate-entitymanager" 라이브러리가 아래에서 보는 것과 같이 무수히 많은 라이브러리를 같이 다운받은 것을 확인할 수 있다. 간단히 보자면 "hibernate-core"와 "javax.persistence-api"(JPA 인터페이스)를 다운받은 것을 알 수 있다. 

아래 "src/main/java" 경로에 "hellojpa"라는 패키지를 생성하자. 그리고 "hellojpa" 패키지에 "Main" 클래스를 생성하자. 

Main 클래스 안에 Main 메서드를 만든 후 잘 실행되는지 실행해보자. 그리고 "hellojpa" 패키지에 "entity"라는 패키지를 만들고 그 안에 Member 클래스를 만들자.

Member 클래스를 작성하자.

  1. package hellojpa.entity;
  2.  
  3. import javax.persistence.Entity;
  4. import javax.persistence.Id;
  5.  
  6. @Entity
  7. public class Member {
  8.       
  9.        @Id
  10.        private Long id;
  11.        private String name;
  12.       
  13.        public Long getId() {
  14.                return id;
  15.        }
  16.        public void setId(Long id) {
  17.                this.id = id;
  18.        }
  19.        public String getName() {
  20.                return name;
  21.        }
  22.        public void setName(String name) {
  23.                this.name = name;
  24.        }
  25. }

라인 6 @Entity 어노테이션은 아래와 같이 javax.persistence 패키지를 선택해야 한다. 라인 9 @Id 어노테이션도 마찬가지로 같은 패키지를 선택해야한다.(라인 3, 4참고). 마지막으로 라인 1 패키지경로가 같은지 확인하자.

persistence.xml 파일을 만들자. JPA가 실행할 때 이 파일을 읽어서 DB에 접속한다던지 일을 하기 때문에 있어야 한다.  아래와 같이 persistence.xml 파일을 만들자.

persistence.xml 파일 안에 아래와 같이 작성하자.

persistence.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
  3.  
  4.     <persistence-unit name="hello">
  5.  
  6.         <properties>
  7.  
  8.             <!-- 필수 속성 -->
  9.             <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
  10.             <property name="javax.persistence.jdbc.user" value="sa"/>
  11.             <property name="javax.persistence.jdbc.password" value="1234"/>
  12.             <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/./test"/>
  13.             <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
  14.  
  15.             <!-- 옵션 -->
  16.             <property name="hibernate.show_sql" value="true" />
  17.             <property name="hibernate.format_sql" value="true" />
  18.             <property name="hibernate.use_sql_comments" value="true" />
  19.  
  20.             <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
  21.         </properties>
  22.     </persistence-unit>
  23.  
  24. </persistence>

애플리케이션 개발

  • 엔티티 매니저 팩토리 설정
  • 엔티티 매니저 설정
  • 트랜잭션
  • 비즈니스 로직(CRUD)

엔티티 매니저 설정

JPA는 Persistence 클래스를 통해서 persistence.xml 설정정보를 읽은 후 EntityManagerFactory를 만든다. EntityManagerFactory는 EntityManager를 만든다. 트랜잭션 단위로 업무를 처리할 때 EntityManager를 새로 만들어야 한다. 

 

Main.java

  1. package hellojpa;
  2.  
  3. import javax.persistence.EntityManagerFactory;
  4. import javax.persistence.Persistence;
  5.  
  6. public class Main {
  7.       
  8.        public static void main(String[] args) {
  9.                EntityManagerFactory emf =
  10.                              Persistence.createEntityManagerFactory("hello");
  11.                System.out.println("Hello");
  12.        }
  13.  
  14. }

Main 클래스에서 라인 9, 10과 같이 코드를 추가하자. 라인 10에 Persistenct.createEntityManagerFactory("hello") 코드에서 createEntityManagerFactory() 메서드에 매개변수로 "hello"를 넘기고 있다. 이는 아래 persistence.xml 파일에서 라인 3 <persistence-unit name="hello"> 태그의 name 속성값인 "hello"를 나타낸다. 즉, 메인 클래스에서 "hello"라는 이름으로 persistence.xml 파일에 있는 설정정보를 가져와서 로딩을 하겠다는 의미이다. 

 

persistence.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
  3.     <persistence-unit name="hello">

위와 같이 Main 클래스를 작성 후 실행해보자.

일단 위와 같이 나오면 정상적으로 실행된 것으로 보면 된다. 실행 후 종료가 안될 것이다. Main 클래스에 아래와 같이 라인 5 emf.close(); 코드를 추가하자. 

  1. public static void main(String[] args) {
  2.                EntityManagerFactory emf =
  3.                              Persistence.createEntityManagerFactory("hello");
  4.                System.out.println("Hello");
  5.                emf.close();
  6.        }

그리고 Main 클래스를 실행하면 정상적으로 종료되는 걸 확인할 수 있다.

 

EntityManagerFactory는 서버를 띄울 때 한번 로딩한다. 그리고 유저가 접근하여 비지니스 로직이 실행될 때마다 EntityManagerFactory에서 EntityManager를 꺼내서 쓴다.  

 

Main 클래스를 아래와 같이 작성하고 실행해보자.

  1. package hellojpa;
  2.  
  3. import javax.persistence.EntityManager;
  4. import javax.persistence.EntityManagerFactory;
  5. import javax.persistence.EntityTransaction;
  6. import javax.persistence.Persistence;
  7.  
  8. import hellojpa.entity.Member;
  9.  
  10. public class Main {
  11.       
  12.        public static void main(String[] args) {
  13.                EntityManagerFactory emf =
  14.                              Persistence.createEntityManagerFactory("hello");
  15.                EntityManager em = emf.createEntityManager();
  16.               
  17.                //JPA 모든 활동은 트랜잭션 안에서 이루지기 때문에 아래와 같이 트랜잭션을 얻는다.
  18.                EntityTransaction tx = em.getTransaction();
  19.                //트랜잭션이 시작된다. 데이터베이스에 접근해서 커넥션을 가지고  실제 트랜잭션을 시작한다.
  20.                tx.begin();
  21.               
  22.                //member 객체를 저장해보자.
  23.                Member member = new Member();
  24.                member.setId(100L);
  25.                member.setName("안녕하세요");
  26.               
  27.                //persist 영구저장하다라는 의미이다.
  28.                em.persist(member);
  29.                tx.commit();
  30.                //EntityManager 쓰고나서 닫아줘야 한다.
  31.                em.close();
  32.                emf.close();
  33.        }
  34.  
  35. }

라인 31 em.close() 와 같이 EntityManager를 꼭 닫아줘야 한다. 데이터베이스 리소스를 쓰고 있기 때문이다. 그리고 라인 32 emf.close() 와 같이 웹 어플리케이션이 종료되면 EntityManagerFactory도 닫아줘야 한다. 

아래와 같이 INSERT 쿼리가 나가는 걸 확인할 수 있다. H2 Console에서 확인해보자.

MEMBER 테이블을 확인하면 데이터가 정상적으로 생성된 것을 확인할 수 있다.

사실 Main 클래스는 아래와 같이 짜는 게 정상이다. 위에서는 테스트를 위해 축약했다.

  1. package hellojpa;
  2.  
  3. import javax.persistence.EntityManager;
  4. import javax.persistence.EntityManagerFactory;
  5. import javax.persistence.EntityTransaction;
  6. import javax.persistence.Persistence;
  7.  
  8. import hellojpa.entity.Member;
  9.  
  10. public class Main {
  11.       
  12.        public static void main(String[] args) {
  13.                EntityManagerFactory emf =
  14.                              Persistence.createEntityManagerFactory("hello");
  15.                EntityManager em = emf.createEntityManager();
  16.               
  17.                //JPA 모든 활동은 트랜잭션 안에서 이루지기 때문에 아래와 같이 트랜잭션을 얻는다.
  18.                EntityTransaction tx = em.getTransaction();
  19.                //트랜잭션이 시작된다. 데이터베이스에 접근해서 커넥션을 가지고  실제 트랜잭션을 시작한다.
  20.                tx.begin();
  21.               
  22.                try {
  23.                       //member 객체를 저장해보자.
  24.                       Member member = new Member();
  25.                       member.setId(100L);
  26.                       member.setName("안녕하세요");
  27.                      
  28.                       //persist 영구저장하다라는 의미이다.
  29.                       em.persist(member);
  30.                       tx.commit();
  31.                } catch (Exception e) {
  32.                       tx.rollback();
  33.                } finally {
  34.                       //EntityManager 쓰고나서 닫아줘야 한다.
  35.                       em.close();
  36.                }
  37.               
  38.                emf.close();
  39.        }
  40.  
  41. }

주의

  • EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유
  • EntityManager는 쓰레드 간에 공유하면 안된다. (사용하고 버려야 한다. 사용자요청이 오면 쓰고 바로 버려야 한다. 다른 유저가 요청 시 EntityManagerFactory에서 EntityManager를 꺼내서 사용해야 한다.)
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행

'IT공부 > JPA' 카테고리의 다른 글

JPA 6강 - JPA 내부구조  (0) 2020.05.22
JPA 5강 - 양방향 매핑  (0) 2020.05.21
JPA 4강 - 연관관계 매핑  (0) 2020.05.21
JPA 3강 - 필드와 컬럼 매핑  (0) 2020.05.21
JPA 1강  (0) 2020.05.19