JPA 프로젝트 생성하고 실행하기

2022. 3. 12. 21:26JPA

JPA 프로젝트 생성

-> H2 데이터베이스를 사용한다.

-> 자바 라이브러리, 빌드 관리와 라이브러리 자동 다운로드 및 의존성 관리를 하는 메이븐을 사용한다.

-> persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="hello">
        <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.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>
</persistence>

☞ JPA설정 파일이다.

☞ persistence-unit name으로 이름을 지정한다.

☞ javax.persistence로 시작하는 것은 JPA표준 속성이다.

☞ "javax.persistence.jdbc.driver" value = org.h2.Driver : 데이터베이스 접근 조건으로 h2 Driver사용함을 나타낸다.

 

◎ 데이터베이스 방언

-> SQL표준을 지키지 않는 특정 데이터베이스만의 고유한 기능을 방언이라고 표현한다. (ex 문자열을 자르는 함수를 SQL표준은 "SUBSTRING()", Oracle은 "SUBSTR()")

-> JPA는 특정 데이터베이스에 종속적이지 않다.

-> 각 데이터베이스가 제공하는 SQL문법과 함수는 다르다.

-> 방언 : SQL표준을 지키지 않는 특정 데이터베이스만의 고유한 특성이다.

-> hibernate.dialect 속성에 지정한다.

 

◎ EntityMangerFactory & EntityManager

-> EntityMangerFactory는 애플리케이션 로딩 시점에 딱 한 번만 만들어야 한다.  데이터베이스와 연결기능도 한다.

-> 실제 데이터베이스에 저장하거나 하는 트랜젝션 단위(고객이 어떤 요청을 하고 나감 등의 과정)마다  EntityManager를 만들어야한다.

 

◎ JPA 구동 방식

-> JPA의 Persistence라는 클래스에서 설정 정보 persistence.xml을 읽어서 EntityManagerFactory를 만들고 필요할 때 마다 EntityManager를 생성하여 실행한다.

 

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");

        em.persist(member);
        tx.commit();
        em.close();
        emf.close();
    }
}

☞ EntityTransaction tx = em.getTransaction();은 트랜젝션을 얻을 수 있다. 

☞ tx.begin();은 트랜젝션을 시작한다.

 

-> Member

@Entity // 이게 있어여 JPA를 사용하는 것으로 인식을 한다.
public class Member {

    @Id
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

☞ @Entity : JPA가 관리할 객체

☞ @Id : 데이터베이스 PK와 매핑

 

-> 결과

☞ 코드를 실행하면 위와 같이 쿼리가 출력된다.

☞ <property name="hibernate.show_sql" value="true"/>은 위와 같은 퀴리를 보여주게 한다.

☞ <property name="hibernate.format_sql" value="true"/>은 위 쿼리처럼 보기 편하게 정리를 한다.

☞ <property name="hibernate.use_sql_comments" value="true"/>은 쿼리가 왜 나왔는지 알려준다.

 

-> h2데이터베이스를 통해 데이터가 저장이 된 것을 확인할 수 있다.

☞ 위 코드는 문제가 발생하면 호출이 되지 않는 문제가 있다.

 

-> 다음과 같이 예외 처리를 하여 문제를 해결한다.

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{

            Member member = new Member();
            member.setId(1L);
            member.setName("HelloJPA"); // 이렇게만 해도 수정 가능 em.persist필요 없다
            
            em.persist(member);
            tx.commit();
        } catch(Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

 

-> 데이터 조회

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            Member findMember = em.find(Member.class, 1L);
            System.out.println("findMember.id = " + findMember.getId());
            System.out.println("findMember.name = " + findMember.getName());


            tx.commit();
        } catch(Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

-> 결과

-> 삭제

☞ 삭제는 위 코드에서 em.remove()를 사용하면 된다.

 

-> 수정

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            Member findMember = em.find(Member.class, 1L);
            findMember.setName("HelloJPA");
            
            tx.commit();
        } catch(Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

-> 결과

-> h2 데이터 확인

☞ 결과를 통해 기존 HelloA에서 HelloJPA로 데이터가 변경된 것을 알 수 있다.

☞ em.persistence사용할 필요 없이 아래의 코드로 데이터를 수정할 수 있다.

Member findMember = em.find(Member.class, 1L);
findMember.setName("HelloJPA");

☞ JPA를 통해 엔티티를 가져오면 JPA가 관리를 한다. JPA가 변경 여부를 트랜젝션 커밋 시점에 체크를 해서 변경이 되었으면 커밋 직적에 업데이트 쿼리를 날리고 트랜젝션 커밋을 한다. 따라서 em.persistence로 저장할 필요없이 위 코드만으로 수정을 할 수 있다.

 

◎ 주의 사항

-> EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에 공유한다.

-> EntityManager는 고객의 요청이 올 때 마다 사용하고 버리고를 반복하기 때문에 스레드 간 공유는 할 수 없다. 

-> JPA의 모든 변경은 트랜젝션 내부에서만 실행되어야 한다.

 

◎ JPQL

-> 가장 단순한 조회 방법이다.

-> 내가 원하는 데이터를 최적화해서 가져올 수 있다.

List<Member> result = em.createQuery("select m from Member as m", Member.class).getResultList();

☞ JPA는 객체를 대상으로 퀴리를 작성한다. 

 

-> 예제

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            List<Member> result = em.createQuery("select m from Member as m", Member.class).getResultList();
            for(Member member:result){
                System.out.println("member.name = " + member.getName());
            }

            tx.commit();
        } catch(Exception e){
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}

 

-> 결과

-> JPA를 사용하면 객체를 중심으로 개발한다. 하지만 데이터를 검색을 해야하는 경우 모든 데이터베이스를 객체로 변환해서 검색하는 것은 불가능하다. 애플리케이션에서 필요한 데이터만 불러오려면 검색 조건이 포함된 SQL이 필요하다. 그러나 이 방식은 데이터베이스에 종속적으로 설계를 해야 한다.

-> JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.

-> SQL은 데이터베이스 테이블을 대상으로 쿼리를 한다.

-> JPQL은 엔티티를 객체를 대상으로 쿼리를 한다. 따라서 데이터베이스 방언을 바꿔도 코드를 변경할 필요가 없다는 장점이 있다.

 

 

★ 참고

자바 ORM 표준 JPA 프로그래밍 - 기본편

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

'JPA' 카테고리의 다른 글

flush  (0) 2023.05.07
더티 체킹  (0) 2023.05.07
식별자 전략  (0) 2023.02.28
JPA  (0) 2023.02.23
JPA  (0) 2022.02.25