본문 바로가기
JPA

[JPA] JPA 소개 및 시작

by 케로베로 2020. 8. 30.

JPA란 무엇인가?

출처: https://ultrakain.gitbooks.io/jpa/content/chapter1/chapter1.3.html

 JPA(Java Persistence API는 자바 진영의 ORM 기술 표준이다 JPA는 애플리케이션과 JDBC 사이에서 동작한다. ORM이란 Object-Relational Mapping 즉 객체와 관계형 데이터베이스를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다. 객체를 DB에 저장할 때 SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 알아서 적절한 SQL을 생성해서 DB에 객체를 저장해준다. 따라서 개발자는 데이터 중심인 관계형 데이터베이스를 사용해도 객체지향 어플리케이션 개발에 집중할 수 있다.

 

 JPA는 자바 ORM 기술에 대한 표준 명세다. 쉽게 이야기해서 인터페이스를 모아둔 것이다. 따라서 JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야하며 이 중 하이버네이트가 가장 대중적이다.

 

왜 JPA를 사용해야 하는가?

-패러다임의 불일치 해결

 관계형 데이터베이스는 데이터 중심으로 구조화되어 있고 집학적인 사고를 요구한다. 글고 객체지향의 추상화, 상속, 다형성 같은 개념이 없다. 객체와 관계형 데이터베이스는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법도 다르다. 이것을 객체와 관계형 데이터베이스의 패러다임의 불일치 문제라 한다. 이러한 문제를 개발자가 해결하려면 많은 시간과 코드가 소비한다. JPA를 이용하면 패러다임의 불일치 문제를 해결해주고 정교한 객체 모델링을 유지하게 도와준다.

 

-생산성

 JPA를 사용하면 반복적인 코드와 CRUD용 SQL을 개발자가 직접하지 않아도 된다. 더 나아가서 JPA에는 CREATE TABLE 같은 DDL 문을 자동으로 생성해주는 기능도 있다. 이런 기능들로 데이터베이스 설계 중심의 패러다임을 객체 중심으로 역전 시킬 수 있다.

 

-유지보수

 SQL을 직접 다루면 엔티티의 사소한 변화에도 등록, 수정, 조회 SQL과 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야 하지만 JPA를 사용하면 이런 과정들을 JPA가 대신 처리해주므로 필드를 추가하거나 삭제해도 수정해야할 코드가 줄어든다.  따라서 개발자가 작성해야 했던 SQL과 코드를 JPA가 대신 처리해주므로 유지보수해야 하는 코드 수가 줄어든다.

 

-성능

 JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공한다. JPA는 애플리케이션과 데이터베이스 사이에서 동작한다. 이렇게 사이에 계층이 하나 더 있으면 최적화 관점에서 시도해 볼 수 있는 것들이 많다. 예를 들어 JPA로 동일 객체를 2번 조회했을 때 두번째 조회는 객체를 재사용한다.

 

-데이터 접근 추상화와 벤더 독립성

 JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공해서 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 한다.

 

-표준

 JPA는 자바 진영의 ORM 기술 표준이고, 표준을 사용한다면 다른 구현 기술로 손쉽게 변경할 수 있다.

 

객체 매핑

 JPA를 사용하려면 가장 먼저 클래스와 테이블을 매핑해야 한다. 이를 위해서는 JPA가 제공하는 매핑 어노테이션을 클래스에 추가해야한다.

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

- @Table : 엔티티 클래스에 매핑할 테이블 정보를 알려준다. name 속성을 사용해서 테이블의 이름을 지정할 수 있으며, 이 어노테이션을 생략하면 클래스 이름을 테이블 이름으로 매핑한다.

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

- @Colomn : 필드를 컬럼에 매핑한다. 마찬가지로 name 속성을 사용하면 테이블의 컬럼 이름을 지정할 수 있으며, 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다.

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;	//	매핑 정보가 없기 때문에 동일한 이름의 컬럼과 매핑
}

 

persistence.xml 설정

 JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리한다. 이 설정 파일이 META-INF/persistence.xml 클래스 패스 경로에 있으면 별도의 설정없이 JPA가 인식할 수 있다. JPA 설정은 영속성 유닛이라는 것부터 시작하는데 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록한다. 그 후 JPA 표준 속성과 하이버 네이트 전용 속성 들을 입력한다.

<persistence-unit name="jpabook"> 	//	영속성 유닛 등록
        <properties>
            <!-- 필수 속성 -->
            //	JDBC 드라이버
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>		
            //	DB 접속 아이디
            <property name="javax.persistence.jdbc.user" value="sa"/>			
            //	DB 접속 패스워드
            <property name="javax.persistence.jdbc.password" value=""/>					
            //	DB 접속 URL
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>	
            //	DB 방언 설정
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />		

            <!-- 옵션 -->
            //	실행한 SQL 출력
            <property name="hibernate.show_sql" value="true" />				
            //	SQL 출력시 보기 쉽게 정렬
            <property name="hibernate.format_sql" value="true" />			
            //	쿼리 출력시 주석도 함께 출력
            <property name="hibernate.use_sql_comments" value="true" />			
            //	JPA 표준에 맞춘 새로운 키 생성 전략 사용
            <property name="hibernate.id.new_generator_mappings" value="true" />	
        </properties>
</persistence-unit>

 

애플리케이션 개발 예시

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

 JPA 애플리케이션 개발 시 코드는 크게 3부분으로 나누어진다.

 

-엔티티 매니저 설정

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

 

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

 

 사용이 끝난 엔티티 매니저와 엔티티 매니저 팩토리는 반드시 종료해야한다.

 

-트랜잭션 관리

 JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 한다. 트랜잭션을 시작하려면 엔티티 매니저에서 트랜잭션 API를 받아와야 한다. 트랜잭션 API를 사용해서 비즈니스 로직이 정상 동작하면 커밋하고 예외 발생 시 롤백한다.

 

-비즈니스 로직

 비즈니스 로직을 보면 등록, 수정, 삭제, 조회 작업이 엔티티 매니저를 통해서 수행된다. 엔티티를 저장하려면 엔티티 매니저의 persist() 메소드에 엔티티를 넘겨주면 된다. 수정의 경우에는 단순히 엔티티의 값만 변경해주면 UPDATE SQL을 생성해서 데이터베이스의 값을 변경한다. 삭제의 경우 엔티티 매니저의 remove() 메소드에 엔티티만 넘겨주면 되고, 조회는 find 메소드를 이용한다. find 메소드는 조회할 엔티티 타입과 식별자 값으로 SELECT SQL을 발생시킨다.

 

 JPA는 SQL을 추상화한 JPQL 이라는 객체지향 쿼리 언어를 제공한다 JPQL은 SQL과 문법이 거의 유사하지만 SQL과 달리 JPQL은 엔티티 객체를 대상으로 쿼리한다. 따라서 JPQL은 데이터베이스의 테이블을 전혀 알지 못한다. JPQL을 사용하기 위해서는 엔티티 매니저의 createQuery 메소드를 실행해서 쿼리 객체를 생성한 후 쿼리 객체의 getResultList() 메소드를 호출하면 된다.

'JPA' 카테고리의 다른 글

[JPA] 프록시와 연관관계 관리  (0) 2020.09.22
[JPA] 고급 매핑  (0) 2020.09.15
[JPA] 연관관계 매핑  (0) 2020.09.10
[JPA] 엔티티 매핑  (0) 2020.09.04
[JPA] 영속성 관리  (0) 2020.08.31