0+ 스프링/0 + 스프링 ORM(JPA)

[JPA] JPA 구동 방식과 간단 실습(CRUD)

힘들면힘을내는쿼카 2023. 2. 9. 23:17
728x90
반응형

[JPA] JPA 구동 방식과 간단 실습(CRUD)

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
이 글은 인프런에서 제공하는 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의를 참고했고
강의 내용을 다시 복습하면서 정리하려는 목적으로 작성합니다.

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

 

 

 

2023.02.08 - [0 + 프로그래밍/0 + JPA] - [JPA] JPA 기초 

 

[JPA] JPA 기초

[JPA] JPA 기초 자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의 이 글은 인프런에서 제공하는 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의를 참고했고 강의 내용을 다시 복습하면서 정리하려는

howisitgo1ng.tistory.com

 

JPAJAVA ApplicationJDBC API 사이에서 동작한다는 것을 지난시간에 배웠습니다.

기본적으로 JPAPersistence 라는 클래스로 시작하고 먼저 설정 정보를 조회하여 EntityManagerFactory라는 클래스를 생성합니다.
그리고 EntityManagerFactory에서 필요할때 마다 EntityManager를 생성하여 사용합니다.
이를 그림으로 표현하면 아래와 같습니다.

기본적인 개념을 알았으니 실습을 진행해 볼까요?

실습 설정

H2 DataBase 설치 및 설정

H2 Database Engine
H2 DataBase 두번째 새 저장소 만들기(create a new database)

META-INF/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="pureJpa">
        <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="123"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/./pure-jpa"/>
            <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>

persistence.xml의 경로는 다음과 같습니다.

JpaMain

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("pureJpa");
    }
}

메인 메소드를 생성하여 잘 동작하는지 확인 합니다.

실습 -회원(CRUD)

  • EntityManagerFactory는 하나만 생성하여 애플리케이션 전체에서 공유 해야합니다.
  • EntityManager는 쓰레드간 공유하면 안됩니다.(사용하고 반드시 버려야 합니다.)
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행해야 합니다.

먼저 회원 Entity를 작성하겠습니다.

Member

@Entity
@Getter // 롬복 사용
public class Member {
    @Id // PK
    private Long id;
    private String name;

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

EntityDB TABLE에 매핑

META-INF/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="pureJpa">
        <class>com.study.purejpa.entity.Member</class>
        <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="123"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/./pure-jpa"/>
            <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>

<class>com.study.purejpa.entity.Member</class>을 추가 합니다.

JpaMain

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

        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻음
        tx.begin(); // 트랜잭션 시작
        try {
            Member member = new Member();
            member.setId(1L);
            member.setName("아이유");
            em.persist(member);

            tx.commit(); // 커밋
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close(); // DB Connection을 사용하여 작업함
        }
        emf.close(); // 애플리케이션이 종료되면 닫아야함
    }
}

결과


오우오우오우!! 신기하지 않습니까? 🕺
쿼리가 자동 생성되었습니다.
create table Member ( … )쿼리가 발생한 이유는 persistence.xml에서
<property name="hibernate.hbm2ddl.auto" value="create" />같이 설정했기 때문 입니다.

 


H2 console 에서도 확인 할수 있습니다.

조회

private static Member findMember(Long id, EntityManager em, EntityManagerFactory emf) {

    EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻음
    Member member = null;
    tx.begin(); // 트랜잭션 시작
    try {
        member = em.find(Member.class, id); // 조회
        tx.commit(); // 커밋
    } catch (Exception e) {
        tx.rollback(); // 롤백
    } finally {
        em.close(); // DB Connection을 사용하여 작업함
    }
    emf.close(); // 애플리케이션이 종료되면 닫아야함
    return member;
}

member = em.find(Member.class, id); // 조회

저장

private static void saveMember(Member member, EntityManager em, EntityManagerFactory emf) {

    EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻음
    tx.begin(); // 트랜잭션 시작
    try {
        em.persist(member); // 저장
        tx.commit(); // 커밋
    } catch (Exception e) {
        tx.rollback(); // 롤백
    } finally {
        em.close(); // DB Connection을 사용하여 작업함
    }
    emf.close(); // 애플리케이션이 종료되면 닫아야함
}

em.persist(member); // 저장

삭제

private static void deleteMember(Long id, EntityManager em, EntityManagerFactory emf) {
    EntityTransaction tx = em.getTransaction();
    tx.begin(); // 트랜잭션 시작

    try {
        Member findMember = em.find(Member.class, id);
        em.remove(findMember); // 삭제

        tx.commit(); // 커밋
    } catch (Exception e) {
        tx.rollback(); // 롤백
    } finally {
        em.close(); // DB Connection을 사용하여 작업함
    }
    emf.close(); // 애플리케이션이 종료되면 닫아야함
}

em.remove(findMember); // 삭제

수정

private static void updateMemberName(Long id, String name, EntityManager em, EntityManagerFactory emf) {
    EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻음
    tx.begin(); // 트랜잭션 시작
    try {
        Member findMember = em.find(Member.class, id);
        findMember.setName(name); // 수정

        tx.commit(); // 커밋
    } catch (Exception e) {
        tx.rollback(); // 롤백
    } finally {
        em.close(); // DB Connection을 사용하여 작업함
    }
    emf.close(); // 애플리케이션이 종료되면 닫아야함
}

findMember.setName(name); // 수정

수정이 특이한데 객체의 값을 변경하고 저장(em.persist(findMember);)하지 않는 다는 점 입니다.
변경 대상(객체)을 찾고, 대상(객체)의 값을 변경하면 update 쿼리가 발생합니다.
이를 변경 감지(dirty checking)이라고 합니다.

더티 체킹이 발생할 수 있는 이유는 바로 em.find(Member.class, id);을 통해서 조회를 하게 되면 JPA가 해당 객체를 관리하게 됩니다. 이를 영속성 컨텍스트에 넣는다고 표현 합니다.
영속성 컨텍스트로 관리되는 객체에 변화가 생기면 이를 JPA가 확인하여 알맞은 쿼리를 생성합니다.

다음시간에는 JPA에서 가장 중요한 영속성 컨텍스트에 대해서 다뤄보겠습니다.

JPQL

JPA를 사용하면 엔티티 객체 중심으로 개발이 가능합니다.
문제는 검색 쿼리 인데, 현업에는 조회를 하는데 더 복잡한 쿼리를 사용합니다.
모든 DB 데이터를 객체로 변환해서 검색하는것은 불가능 합니다..😵‍💫
결국 애플리케이션이 필요한 데이터만 DB에서 불러오려면 검색 조건이 포함된 SQL이 필요합니다.

그래서 등장한 것이 JPQL 입니다.

JPQLSQL을 추상화한 쿼리 입니다.
테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리입니다.
SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않습니다.

한마디로 JPQL은 객체 지향 SQL이라고 말씀드릴수 있겠습니다.

JPQL에 대한 포스팅은 다음 더 상세히 다루겠습니다.

 

 

728x90
반응형