본문 바로가기

IT/데이터베이스

JPA 공부 - 2

반응형

2021/01/18 - [IT/데이터베이스] - JPA 공부 - 1

 

JPA 공부 - 1

2021/01/17 - [IT/데이터베이스] - JPA 공부 - 0 1. JAP 소개 1.1 SQL을 직접 다룰 때 발생하는 문제점 관계형 데이터베이스는 가장 대중적이고 신뢰할 만한 안전한 저장소 JDBC API 를 사용해서 SQL을 데이터

demoversion.tistory.com

2. JPA 시작

2.1 이클립스 설치와 프로젝트 불러오기
예제 경로 https://github.com/holyeye/jpabook
2.2 H2 데이터베이스 설치
다운로드 경로 : https://www.h2database.com/
2.3 라이브러리와 프로젝트 구조
위 3개 챕터는 설정이라 넘어감

2.4 객체 매핑 시작

  • 회원 테이블

    CREATE TABLE MEMBER(
        ID VARCHAR(255) PRIMARY KEY,
        NAME VARCHAR(255),
        AGE INTEGER NOT NULL
    );
  • 회원 클래스

    public class Member {
        private String id;
        private String username;
        private Integer age;
    
        // getter, setter
    }
  • 회원 클래스와 회원 테이블 매핑 정보

    • 클래스와 테이블 : Member - MEMBER
    • 기본 키 : id - ID
    • 필드와 컬럼 : username - NAME
    • 필드와 컬럼 : age - AGE
  • JPA가 제공하는 매핑 어노테이션 추가

    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; //매핑정보가 없는 필드
    }
    클래스와 테이블 매핑
  • @Entity, @Table, @Column 이 매핑 정보다.

  • JPA는 어노테이션을 분석해서 어떤 객체가 어떤 테이블과 관계가 있는지 알아낸다.

  • @Entity

    • 이 클래스를 테이블과 매핑한다고 JPA에게 알려준다. 이렇게 @Entity 가 사용된 클래스를 엔티티 클래스라고 한다.
  • @Table

    • 엔티티 클래스에 매핑할 테이블 정보를 알려준다.
    • name 속성을 사용해 Member 엔티티를 MEMBER 테이블에 매핑했다.
    • 이 어노테이션을 생략하면 클래스 이름으르 테이블 이름(더 정확히는 엔티티 이름)으로 매핑한다.
  • @Id

    • 엔티티 클래스의 필드를 테이블의 기본 키에 매핑한다.
    • 이렇게 @Id 가 사용된 필드를 식별자 필드라고 한다.
  • @Column

    • 필드를 컬럼에 매핑한다.
  • 매핑 정보가 없는 필드

    • 매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다.
    • 대소문자를 구분하는 데이터베이스를 사용한다면 @Column(name="AGE") 처럼 명시적으로 매핑해야 한다.

2.5 persistence.xml 설정

  • JPA는 psersistence.xml 을 사용해 필요한 설정 관리

  • META-INF/persistence.xml 클래스 패스 경로에 있으면 JPA가 인식

  • persistence.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2"> <!-- JPA 2.2 버전을 사용하기 위해서 표시 -->
    <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" />
        </properties>
    </persistence-unit>
    </persistence>
  • XML 네임스페이스와 JPA 사용 버전 표시

    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
  • JPA는 영속성 유닛을 일반적으로 데이터베이스 하나당 하나의 영속성 유닛을 등록한다.

  • 그리고 영속성 유닛에 고유한 이름을 부여해야 하는데 예제에서는 jpabook 이라는 이름을 사용함

    <persistence-unit name="jpabook">
  • JPA 표준 속성

    • javax.persistence.jdbc.driver : JDBC 드라이버
    • javax.persistence.jdbc.user : 데이터베이스 접속 아이디
    • javax.persistence.jdbc.password : 데이터베이스 접속 아이디
    • javax.persistence.jdbc.url : 데이터베이스 접속 URL
  • 하이버네이트 속성

    • hibernate.dialect : 데이터베이스 Dialect(방언) 설정
  • javax.persistence 으로 시작하는 속성은 특정 구현체에 종속되지 않음

  • hibernate 로 시작하는 속성은 하이버네이트 전용속성

2.5.1 데이터베이스 Dialect(방언)

  • JPA는 데이터베이스에 종속적이지 않은 기술
  • 데이터베이스가 제공하는 SQL 문법과 함수가 조금씩 다르다는 문제점이 있다.
    • 데이터 타입 : MYSQL - VARCHAR / 오라클 - VARCHAR2
    • 다른 함수명 : SQL 표준 - SUBSTRING() / 오라클 - SUBSTR()
    • 페이징 처리 : MYSQL - LIMIT / 오라클 - ROWNUM
  • 이처럼 SQL표준이 아니거나 특정 데이터베이스만의 고유 기능을 JPA에서는 Dialect(방언) 이라고 부른다.
  • 하이버네이트를 포함한 대부분의 JPA 구현체들은 이런 문제를 해결하기위해 다양한 데이터베이스 방언 클래스를 제공한다.
  • 하이버네이트가 제공하는 대표적인 데이터베이스 방언
    • H2 : org.hibernate.dialect.H2Dialect
    • 오라클 10g : org.hibernate.dialect.Oracle10gDialect
    • MySQL : org.hibernate.dialect.MySQL5InnoDBDialect

2.6 애플리케이션 개발

  • 시작코드

    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){
        }
    }
  • 코드는 크게 3부분으로 나뉨

    • 엔티티 매니저 설정
    • 트랜잭션 관리
    • 비즈니스 로직

2.6.1 엔티티 매니저 설정

엔티티 매니저 생성 과정

  • 엔티티 매니저 팩토리 생성
    • Persistence 클래스를 사용해 매니저 팩토리를 생성해서 JPA를 사용할 수 있게 준비한다.
    • 설정한 이름의 영속성 유닛을 찾아 엔티티 매니저 팩토리를 생성한다.
    • 설정 정보를 읽어서 매니저 기반객체를 만들고, 구현체에 따라서 커넥션 풀도 생성하므로 엔티티 매니저 팩토리를 생성하는 비용은 아주 크다.
    • 그렇기 때문에 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 한다.
  • 엔티티 매니저 생성
    EntityManager em = emf.createEntityManager();
    • 엔티티 매니저 팩토리에서 엔티티 매니저를 생성한다.
    • 에티티 매니저를 사용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다.
    • 개발자는 엔티티 매니저를 가상의 데이터베이스로 생각할 수 있다.
    • 데이터베이스 커텍션과 밀접한 관계가 있으므로 스레드간에 공유하거나 재사용하면 안된다.
  • 종료
    • 사용이 끝난 엔티티 매니저는 종료 해주어야 한다.
    • 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 종료해 주어야 한다.

2.6.2 트랜잭션 관리

  • 트랜잭션을 사용하려면 엔티티 매니저에서 트랜잭션 API를 받아와야 한다.

    // 트랜잭션 획득
    EntityTransaction tx = em.getTransaction();
    
    try{
        tx.begin(); //트랜잭션 시작
        logic(em);
        tx.commit(); // 트랜잭션 커밋
    } catch (Exception e){
        tx.rollback(); // 롤백
    }
  • 비즈니스 로직의 정상 / 예외 에따라 커밋 / 롤백을 한다.

2.6.3 비즈니스 로직

  • 비즈니스 로직 코드

    private static void logic(EntityManager em){
    
        String id = "id1";
        Member member = new Member();
        member.setId(id);
        member.setUsername("demo");
        member.setAge(30);
    
        // 등록
        em.persist(member);
    
        // 수정
        member.setAge(31);
    
        // 한건 조회
        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("member.size=" + members.size());
    
        // 삭제
        em.remove(members);
    }
  • 비즈니스 로직을 보면 등록/수정/삭제/조회 작업이 엔티티 매니저를 통해서 수행되는 것을 알 수 있다.

  • 등록

    String id = "id1";
    Member member = new Member();
    member.setId(id);
    member.setUsername("demo");
    member.setAge(30);
    
    // 등록
    em.persist(member);
    • 엔티티를 저장하려면 엔티티 매니저의 persist() 메소드에 저장할 엔티티를 넘겨주면 된다.
    • 실행 쿼리
      insert into MEMBER (age, NAME, ID) values (?, ?, ?)
  • 수정

    member.setAge(31);
    • update 와 비슷한 메소드를 호출하지 않고 단순히 엔티티 값만 변경
    • JPA는 어떤 엔티티가 변경되었는지 추적하는 기능ㅇ르 갖추고 있음
    • 실행 쿼리
      update
          MEMBER
      set
          age=?,
          NAME=?
      where
          ID=?
  • 삭제

    em.remove(members);
    • 엔티티를 삭제하려면 엔티티 매니저의 remove() 메소드에 삭제하려는 엔티티를 넘겨준다.
    • 실행 쿼리
      delete from MEMBER where ID=?
  • 한건 조회

     Member findMember = em.find(Member.class, id);
    • find() 메소드는 조회할 엔티티 타입과 @Id로 데이터베이스 테이블의 기본키와 매핑한 식별자 값으로 엔티티 하나를 조회하는 가장 단순한 메소드다.
    • 실행 쿼리
      select * from member where id=?

2.6.4 JPQL

  • 하나 이상의 회원 목록 조회하는 코드
    List<Member> members =
            em.createQuery("select m from Member m", Member.class)
            .getResultList();
  • JPA는 엔티티 객체를 중심으로 개발하므로 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
  • 데이터베이스의 모든 데이터를 애플리케이션으로 불러와 엔티티 객체로 변경한 다음 검색하는 것은 불가능 하다.
  • 필요한 데이터만 불러오기위해 결국 검색 조건이 포함된 SQL을 사용해야 한다.
  • JPA는 JPQL(Java Persistence Query Language) 이라는 객체지향 쿼리 언어를 제공한다.
  • 차이점
    • JPQL은 에닡티 객체를 대상으로 한다.
    • SQL은 데이터베이스 테이블을 대상으로 한다.
  • from Member 부분은 엔티티 객체를 말하는 것이지 MEMBER 테이블이 아니다.
  • JPQL은 데이터베이스 테이블을 전혀 알지 못한다.
반응형

'IT > 데이터베이스' 카테고리의 다른 글

JPA 공부 - 5  (0) 2021.02.07
JPA 공부 - 4  (0) 2021.01.29
JPA 공부 - 1  (0) 2021.01.18
JPA 공부 - 0  (0) 2021.01.17
백업과 복구  (0) 2021.01.09