JPA의 구동방식

so.oy·2024년 5월 31일
1

JPA

목록 보기
1/3

본 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의를 수강하고 정리한 글입니다.

JPA의 동작 방식을 알아보자!

위의 그림을 보고 설명하자면,
먼저 JPA는 Persistence 클래스가 존재한다. 이 클래스는 개발자가 작성한 persistence.xml에서 설정 정보를 읽어와 EntityManagerFactiory라는 클래스를 만든다.
이렇게 만든 EntityManagerFactory에서는 뭔가 필요할 때마다 EntityManager를 찍어내 만든다.

🔗 코드로 확인하기

public class JpaMain {

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

        em.close();
        emf.close();
    }
}

해당 코드를 처음부터 자세히 확인해보자.

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

Persistence라는 클래스의 createEntityManagerFactory()를 통해서 EntityManagerFactory를 반환해 준다.
여기에서 createEntityManagerFactory()안에는 PersistenceUnitName을 넘기라고 한다.

이것은 persistence.xml 파일의 persistence-unit에 설정한 name을 넘겨주면 된다.

public class JpaMain {

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

        em.close();
        emf.close();
    }
}

다음은 EntityManagerFactory에서 createEntityManager()를 꺼낸다.
실제 애플리케이션이 끝나면 EntityManagerFactory를 닫아주기 위해서 close(); 해준다.

🔍 동작 확인하기

위의 내용을 코드를 통해 확인해보자!

저장하기

데이터베이스에 Member 테이블을 생성해주고, JPA에 엔티티를 추가해준다.
그리고 아래와 같이 member를 생성해준다.

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

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

        em.persist(member);

        em.close();
        emf.close();
    }

하지만 이렇게 실행할 경우 에러가 발생하는데, JPA는 데이터를 변경하는 작업은 반드시 Transaction 안에서 작업해야 하기 때문이다.

여기서 중요한 것은 엔티티 매니저 팩토리는 애플리케이션 로딩 시점에 하나만 생성하여야 하고, 트랜잭션 단위는 DB 커넥션을 얻어 쿼리를 날리고 종료되는 단위마다 엔티티 매니저를 통해 실행된다. 간단하게 생각하자면 엔티티 매니저는 DB 커넥션이라고 할 수 있다.

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();
    }
  1. 엔티티 매니저에서 getTransaction()으로 트랜잭션을 얻는다.
  2. begin() - 트랜잭션 시작
  3. member를 만들고
  4. em.persist(member)로 member를 저장
  5. tx.commit() - 커밋



쿼리와 데이터베이스에 helloA 멤버가 저장된 것을 확인할 수 있다.

또한 이것으로 확인 할 수 있는 것은, 내가 직접 쿼리를 작성할 필요 없이, JPA가 매핑정보를 통해 모든 것을 해준다는 것이다.


위와 같이 코드를 작성할 경우 문제 발생 가능성이 존재한다.
만약 em.persist(member);tx.commit(); 시점에 문제가 생기게 되면, EntityManager close()와 EntityManagerFactory close()가 모두 호출되지 않기 때문이다.

따라서 try-catch 문을 통해 문제가 일어났을 경우에도 코드가 올바르게 동작하도록 수정해주어야 한다.

    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(2L);
            member.setName("HelloB");

            em.persist(member);
            tx.commit();

        } catch (Exception e) {
            tx.rollback();

        } finally {
            em.close();
        }
        emf.close();
    }
  1. try문 안에 시도할 코드를 넣어준다. Member를 생성하고, commit()한다.
  2. 만약 이 과정까지에서 문제가 발생한다면 catch문에서 Exception이 발생하고 rollback() 한다.
  3. 작업이 끝나면 finally문에서 EntityManager를 닫아준다.
    EntityManager가 결국 내부적으로 데이터베이스 커넥션을 얻어 동작하는 것이기 때문에 반드시 닫아주는 것을 잊지 말자.
  4. 전체 애플리케이션이 끝나면 EntityManagerFactory까지 close()해준다.

이렇게 JPA의 동작에 대해서 알아보았다. 하지만 실제로는 이렇게 EntityManager를 생성할 필요 없이 spring이 이러한 것을 해주기 때문에 호출해서 더욱 편하게 사용할 수 있다.

조회하기

 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.getName());
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();

        } finally {
            em.close();
        }
        emf.close();
    }
  1. EntityManager에서 find()해준다. 이 엔티티 매니저는 자바 컬렉션과 같이 이해하면 된다.


select 쿼리로 회원을 찾은 것을 볼 수 있다.

삭제하기

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

            em.remove(findMember);

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

        } finally {
            em.close();
        }
        emf.close();
    }

remove(); 메소드 안에 삭제할 멤버를 넣어주면 Delete 쿼리가 나가면서 삭제된다.

수정하기

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

set() 메서드로 변경할 이름으로 바꾸어준다.
여기서 em.persist로 변경한 이름을 저장해주어야 하는게 아닌가? 라는 생각을 할 수도 있지만, 저장하지 않아도 된다.

쿼리를 확인해보면 UPDATE 쿼리가 나간 것을 볼 수 있다.

데이터베이스에 변경한 이름인 helloJPA로 이름이 변경된 것을 확인했다.

그렇다면 저장하지 않았음에도 어떻게 해서 이름을 변경할 수 있는 것일까?
그 이유는 JPA를 통해서 엔티티를 가져오게 되면, 가져온 엔티티는 JPA가 관리를 하게 된다. 이후 트랜잭션 커밋 시점에 관리되는 엔티티는 변경 사항을 체크한다. 트랜잭션이 커밋하기 직전에 UPDATE 쿼리를 실행해 변경사항을 수정하고 트랜잭션이 커밋된다.

0개의 댓글