🔙뒤로가기

구동 확인

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

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

        EntityManager entityManager = emf.createEntityManager();
        // 실제 코드 작성 부분

        entityManager.close();

        emf.close();
    }
}

H2에 테이블 만들기

create table Member ( 
 id bigint not null, 
 name varchar(255), 
 primary key (id) 
)

엔티티 만들기

package hellojpa;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
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;
    }
}

Main 애플리케이션으로 CRUD 테스트

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

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(4l);
            member.setName("test");
            em.persist(member);

            Member findMember = em.find(Member.class, 4l);
            System.out.println("findMember.getId() = " + findMember.getId());
            System.out.println("findMember.getName() = " + findMember.getName());

            member.setName("testUpdate");
						em.merge(member);

            Member updatedMember = em.find(Member.class, 4l);
            System.out.println("updatedMember.getId() = " + updatedMember.getId());
            System.out.println("updatedMember.getName() = " + updatedMember.getName());

            em.remove(member);

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

        emf.close();
    }
}

jdbc메소드를 통해 저장을 했으니 그 객체를 다시 불러온다는 취지로 em.find() 메소드를 사용하고, 이전에 저장했던 식별자인 4l 값을 파라미터로 전달했다. 그리고 그 객체를 findMember라고 다시 정의했다. 그리고 그 객체를 통해 getter를 사용해 엔티티 정보를 불러와 콘솔에 출력했다. 업데이트도 마찬가지로 merge() 로 데이터를 병합한 후 다시 find() 메소드로 updateMember 객체를 가져와 getter를 사용하길 반복했다.

<aside> ⚠️ 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에 공유한다. 엔티티 매니저는 thread 간에 공유X (사용하고 버려야 한다.) JPA의 모든 데이터 변경은 Transaction 안에서 실행된다.

</aside>

구동 로그

findMember.getId() = 4
findMember.getName() = test
updatedMember.getId() = 4
updatedMember.getName() = testUpdate
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            member
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* delete hellojpa.Member */ delete 
        from
            member 
        where
            id=?

<aside> ⚠️ 로그 확인 결과는 이상하다. println() 은 맨 위에서 나오고, 정작 그 사이사이에 있을 것으로 기대했던 SQL문들은 마지막에 모여있다. 로그의 위치도 이상하고, 분명 em.find()merge() 메소드를 사용했는데 어째서 SELECT, UPDATE SQL의 흔적은 로그에 남지 않았을까?

</aside>

사실 위 코드는 문법적으로는 별 문제가 없기 때문에 얼핏 정상적으로 작동하는 것처럼 보이지만, 이것은 JPA의 자동화에 의해 불필요한 호출이 “생략된” 것에 가깝다. 아래는 수정된 코드이다.

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

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(4l);
            member.setName("test");
            em.persist(member);

//						Member findMember = em.find(Member.class, 4l);
//            System.out.println("findMember.getId() = " + findMember.getId());
//            System.out.println("findMember.getName() = " + findMember.getName());
            System.out.println("findMember.getId() = " + member.getId());
            System.out.println("findMember.getName() = " + member.getName());

            member.setName("testUpdate");
//            em.merge(member);
//            Member updatedMember = em.find(Member.class, 4l);
//            System.out.println("updatedMember.getId() = " + updatedMember.getId());
//            System.out.println("updatedMember.getName() = " + updatedMember.getName());

            System.out.println("updatedMember.getId() = " + member.getId());
            System.out.println("updatedMember.getName() = " + member.getName());

            em.remove(member);

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

        emf.close();
    }
}

첫번째 코드에서 사용했던 find 메소드를 모두 뺐고, 업데이트를 위한 merge조차 없앴다. 업및 db에서 다시 데이터를 꺼내오는 과정까지도 생략해버렸다. 과연 로그는 어떻게 나올까?

findMember.getId() = 4
findMember.getName() = test
updatedMember.getId() = 4
updatedMember.getName() = testUpdate
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            member
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* delete hellojpa.Member */ delete 
        from
            member 
        where
            id=?

완전히 동일하다. 어떻게 이런 일이 가능할까? 이 작동 원리를 이해하려면 JPA가 가진 막강한 “캐시” 작동 방식을 이해해야 한다. 첫 시간에 어렴풋이 언급한 JPA의 장점을 구체적으로 확인할 수 있다.

이 캐시 기능에 대해서는 엔티티 관리방법 “캐시” 에서 알아보자.